forked from openlp/openlp
head
This commit is contained in:
commit
a6422aa58b
|
@ -111,10 +111,10 @@ class OpenLP(QtGui.QApplication):
|
||||||
# Decide how many screens we have and their size
|
# Decide how many screens we have and their size
|
||||||
screens = ScreenList.create(self.desktop())
|
screens = ScreenList.create(self.desktop())
|
||||||
# First time checks in settings
|
# First time checks in settings
|
||||||
has_run_wizard = Settings().value(u'general/has run wizard')
|
has_run_wizard = Settings().value(u'core/has run wizard')
|
||||||
if not has_run_wizard:
|
if not has_run_wizard:
|
||||||
if FirstTimeForm(screens).exec_() == QtGui.QDialog.Accepted:
|
if FirstTimeForm(screens).exec_() == QtGui.QDialog.Accepted:
|
||||||
Settings().setValue(u'general/has run wizard', True)
|
Settings().setValue(u'core/has run wizard', True)
|
||||||
# Correct stylesheet bugs
|
# Correct stylesheet bugs
|
||||||
application_stylesheet = u''
|
application_stylesheet = u''
|
||||||
if not Settings().value(u'advanced/alternate rows'):
|
if not Settings().value(u'advanced/alternate rows'):
|
||||||
|
@ -126,7 +126,7 @@ class OpenLP(QtGui.QApplication):
|
||||||
application_stylesheet += NT_REPAIR_STYLESHEET
|
application_stylesheet += NT_REPAIR_STYLESHEET
|
||||||
if application_stylesheet:
|
if application_stylesheet:
|
||||||
self.setStyleSheet(application_stylesheet)
|
self.setStyleSheet(application_stylesheet)
|
||||||
show_splash = Settings().value(u'general/show splash')
|
show_splash = Settings().value(u'core/show splash')
|
||||||
if show_splash:
|
if show_splash:
|
||||||
self.splash = SplashScreen()
|
self.splash = SplashScreen()
|
||||||
self.splash.show()
|
self.splash.show()
|
||||||
|
@ -147,7 +147,7 @@ class OpenLP(QtGui.QApplication):
|
||||||
self.processEvents()
|
self.processEvents()
|
||||||
if not has_run_wizard:
|
if not has_run_wizard:
|
||||||
self.main_window.first_time()
|
self.main_window.first_time()
|
||||||
update_check = Settings().value(u'general/update check')
|
update_check = Settings().value(u'core/update check')
|
||||||
if update_check:
|
if update_check:
|
||||||
VersionThread(self.main_window).start()
|
VersionThread(self.main_window).start()
|
||||||
self.main_window.is_display_blank()
|
self.main_window.is_display_blank()
|
||||||
|
@ -305,8 +305,10 @@ def main(args=None):
|
||||||
# Instance check
|
# Instance check
|
||||||
if application.is_already_running():
|
if application.is_already_running():
|
||||||
sys.exit()
|
sys.exit()
|
||||||
|
# Remove/convert obsolete settings.
|
||||||
|
Settings().remove_obsolete_settings()
|
||||||
# First time checks in settings
|
# First time checks in settings
|
||||||
if not Settings().value(u'general/has run wizard'):
|
if not Settings().value(u'core/has run wizard'):
|
||||||
if not FirstTimeLanguageForm().exec_():
|
if not FirstTimeLanguageForm().exec_():
|
||||||
# if cancel then stop processing
|
# if cancel then stop processing
|
||||||
sys.exit()
|
sys.exit()
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
The :mod:`lib` module contains most of the components and libraries that make
|
The :mod:`lib` module contains most of the components and libraries that make
|
||||||
OpenLP work.
|
OpenLP work.
|
||||||
"""
|
"""
|
||||||
|
from __future__ import division
|
||||||
from distutils.version import LooseVersion
|
from distutils.version import LooseVersion
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
|
@ -155,7 +156,7 @@ def build_icon(icon):
|
||||||
|
|
||||||
``icon``
|
``icon``
|
||||||
The icon to build. This can be a QIcon, a resource string in the form ``:/resource/file.png``, or a file
|
The icon to build. This can be a QIcon, a resource string in the form ``:/resource/file.png``, or a file
|
||||||
location like ``/path/to/file.png``.
|
location like ``/path/to/file.png``. However, the **recommended** way is to specify a resource string.
|
||||||
"""
|
"""
|
||||||
button_icon = QtGui.QIcon()
|
button_icon = QtGui.QIcon()
|
||||||
if isinstance(icon, QtGui.QIcon):
|
if isinstance(icon, QtGui.QIcon):
|
||||||
|
@ -202,12 +203,13 @@ def create_thumb(image_path, thumb_path, return_icon=True, size=None):
|
||||||
States if an icon should be build and returned from the thumb. Defaults to ``True``.
|
States if an icon should be build and returned from the thumb. Defaults to ``True``.
|
||||||
|
|
||||||
``size``
|
``size``
|
||||||
Allows to state a own size to use. Defaults to ``None``, which means that a default height of 88 is used.
|
Allows to state a own size (QtCore.QSize) to use. Defaults to ``None``, which means that a default height of 88
|
||||||
|
is used.
|
||||||
"""
|
"""
|
||||||
ext = os.path.splitext(thumb_path)[1].lower()
|
ext = os.path.splitext(thumb_path)[1].lower()
|
||||||
reader = QtGui.QImageReader(image_path)
|
reader = QtGui.QImageReader(image_path)
|
||||||
if size is None:
|
if size is None:
|
||||||
ratio = float(reader.size().width()) / float(reader.size().height())
|
ratio = reader.size().width() / reader.size().height()
|
||||||
reader.setScaledSize(QtCore.QSize(int(ratio * 88), 88))
|
reader.setScaledSize(QtCore.QSize(int(ratio * 88), 88))
|
||||||
else:
|
else:
|
||||||
reader.setScaledSize(size)
|
reader.setScaledSize(size)
|
||||||
|
@ -260,8 +262,8 @@ def resize_image(image_path, width, height, background=u'#000000'):
|
||||||
log.debug(u'resize_image - start')
|
log.debug(u'resize_image - start')
|
||||||
reader = QtGui.QImageReader(image_path)
|
reader = QtGui.QImageReader(image_path)
|
||||||
# The image's ratio.
|
# The image's ratio.
|
||||||
image_ratio = float(reader.size().width()) / float(reader.size().height())
|
image_ratio = reader.size().width() / reader.size().height()
|
||||||
resize_ratio = float(width) / float(height)
|
resize_ratio = width / height
|
||||||
# Figure out the size we want to resize the image to (keep aspect ratio).
|
# Figure out the size we want to resize the image to (keep aspect ratio).
|
||||||
if image_ratio == resize_ratio:
|
if image_ratio == resize_ratio:
|
||||||
size = QtCore.QSize(width, height)
|
size = QtCore.QSize(width, height)
|
||||||
|
@ -282,7 +284,7 @@ def resize_image(image_path, width, height, background=u'#000000'):
|
||||||
new_image = QtGui.QImage(width, height, QtGui.QImage.Format_ARGB32_Premultiplied)
|
new_image = QtGui.QImage(width, height, QtGui.QImage.Format_ARGB32_Premultiplied)
|
||||||
painter = QtGui.QPainter(new_image)
|
painter = QtGui.QPainter(new_image)
|
||||||
painter.fillRect(new_image.rect(), QtGui.QColor(background))
|
painter.fillRect(new_image.rect(), QtGui.QColor(background))
|
||||||
painter.drawImage((width - real_width) / 2, (height - real_height) / 2, preview)
|
painter.drawImage((width - real_width) // 2, (height - real_height) // 2, preview)
|
||||||
return new_image
|
return new_image
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
"""
|
"""
|
||||||
Provide additional functionality required by OpenLP from the inherited QDockWidget.
|
Provide additional functionality required by OpenLP from the inherited QDockWidget.
|
||||||
"""
|
"""
|
||||||
|
from __future__ import division
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from PyQt4 import QtGui
|
from PyQt4 import QtGui
|
||||||
|
@ -55,7 +56,7 @@ class OpenLPDockWidget(QtGui.QDockWidget):
|
||||||
self.setWindowIcon(build_icon(icon))
|
self.setWindowIcon(build_icon(icon))
|
||||||
# Sort out the minimum width.
|
# Sort out the minimum width.
|
||||||
screens = ScreenList()
|
screens = ScreenList()
|
||||||
main_window_docbars = screens.current[u'size'].width() / 5
|
main_window_docbars = screens.current[u'size'].width() // 5
|
||||||
if main_window_docbars > 300:
|
if main_window_docbars > 300:
|
||||||
self.setMinimumWidth(300)
|
self.setMinimumWidth(300)
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
|
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
|
||||||
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
from __future__ import division
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from PyQt4 import QtWebKit
|
from PyQt4 import QtWebKit
|
||||||
|
@ -276,7 +276,7 @@ def build_background_css(item, width):
|
||||||
``item``
|
``item``
|
||||||
Service Item containing theme and location information
|
Service Item containing theme and location information
|
||||||
"""
|
"""
|
||||||
width = int(width) / 2
|
width = int(width) // 2
|
||||||
theme = item.themedata
|
theme = item.themedata
|
||||||
background = u'background-color: black'
|
background = u'background-color: black'
|
||||||
if theme:
|
if theme:
|
||||||
|
|
|
@ -102,7 +102,9 @@ class MediaManagerItem(QtGui.QWidget):
|
||||||
self.setupUi()
|
self.setupUi()
|
||||||
self.retranslateUi()
|
self.retranslateUi()
|
||||||
self.auto_select_id = -1
|
self.auto_select_id = -1
|
||||||
Registry().register_function(u'%s_service_load' % self.plugin.name, self.service_load)
|
# Need to use event as called across threads and UI is updated
|
||||||
|
QtCore.QObject.connect(self, QtCore.SIGNAL(u'%s_go_live' % self.plugin.name), self.go_live_remote)
|
||||||
|
QtCore.QObject.connect(self, QtCore.SIGNAL(u'%s_add_to_service' % self.plugin.name), self.add_to_service_remote)
|
||||||
|
|
||||||
def required_icons(self):
|
def required_icons(self):
|
||||||
"""
|
"""
|
||||||
|
@ -424,7 +426,7 @@ class MediaManagerItem(QtGui.QWidget):
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError(u'MediaManagerItem.on_delete_click needs to be defined by the plugin')
|
raise NotImplementedError(u'MediaManagerItem.on_delete_click needs to be defined by the plugin')
|
||||||
|
|
||||||
def onFocus(self):
|
def on_focus(self):
|
||||||
"""
|
"""
|
||||||
Run when a tab in the media manager gains focus. This gives the media
|
Run when a tab in the media manager gains focus. This gives the media
|
||||||
item a chance to focus any elements it wants to.
|
item a chance to focus any elements it wants to.
|
||||||
|
@ -481,6 +483,15 @@ class MediaManagerItem(QtGui.QWidget):
|
||||||
else:
|
else:
|
||||||
self.go_live()
|
self.go_live()
|
||||||
|
|
||||||
|
def go_live_remote(self, message):
|
||||||
|
"""
|
||||||
|
Remote Call wrapper
|
||||||
|
|
||||||
|
``message``
|
||||||
|
The passed data item_id:Remote.
|
||||||
|
"""
|
||||||
|
self.go_live(message[0], remote=message[1])
|
||||||
|
|
||||||
def go_live(self, item_id=None, remote=False):
|
def go_live(self, item_id=None, remote=False):
|
||||||
"""
|
"""
|
||||||
Make the currently selected item go live.
|
Make the currently selected item go live.
|
||||||
|
@ -523,6 +534,15 @@ class MediaManagerItem(QtGui.QWidget):
|
||||||
for item in items:
|
for item in items:
|
||||||
self.add_to_service(item)
|
self.add_to_service(item)
|
||||||
|
|
||||||
|
def add_to_service_remote(self, message):
|
||||||
|
"""
|
||||||
|
Remote Call wrapper
|
||||||
|
|
||||||
|
``message``
|
||||||
|
The passed data item:Remote.
|
||||||
|
"""
|
||||||
|
self.add_to_service(message[0], remote=message[1])
|
||||||
|
|
||||||
def add_to_service(self, item=None, replace=None, remote=False):
|
def add_to_service(self, item=None, replace=None, remote=False):
|
||||||
"""
|
"""
|
||||||
Add this item to the current service.
|
Add this item to the current service.
|
||||||
|
@ -564,12 +584,15 @@ class MediaManagerItem(QtGui.QWidget):
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def service_load(self, message):
|
def service_load(self, item):
|
||||||
"""
|
"""
|
||||||
Method to add processing when a service has been loaded and individual service items need to be processed by the
|
Method to add processing when a service has been loaded and individual service items need to be processed by the
|
||||||
plugins.
|
plugins.
|
||||||
|
|
||||||
|
``item``
|
||||||
|
The item to be processed and returned.
|
||||||
"""
|
"""
|
||||||
pass
|
return item
|
||||||
|
|
||||||
def check_search_result(self):
|
def check_search_result(self):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -103,7 +103,7 @@ class Plugin(QtCore.QObject):
|
||||||
``add_export_menu_Item(export_menu)``
|
``add_export_menu_Item(export_menu)``
|
||||||
Add an item to the Export menu.
|
Add an item to the Export menu.
|
||||||
|
|
||||||
``create_settings_Tab()``
|
``create_settings_tab()``
|
||||||
Creates a new instance of SettingsTabItem to be used in the Settings
|
Creates a new instance of SettingsTabItem to be used in the Settings
|
||||||
dialog.
|
dialog.
|
||||||
|
|
||||||
|
@ -252,7 +252,7 @@ class Plugin(QtCore.QObject):
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def create_settings_Tab(self, parent):
|
def create_settings_tab(self, parent):
|
||||||
"""
|
"""
|
||||||
Create a tab for the settings window to display the configurable options
|
Create a tab for the settings window to display the configurable options
|
||||||
for this plugin to the user.
|
for this plugin to the user.
|
||||||
|
|
|
@ -153,7 +153,7 @@ class PluginManager(object):
|
||||||
"""
|
"""
|
||||||
for plugin in self.plugins:
|
for plugin in self.plugins:
|
||||||
if plugin.status is not PluginStatus.Disabled:
|
if plugin.status is not PluginStatus.Disabled:
|
||||||
plugin.create_settings_Tab(self.settings_form)
|
plugin.create_settings_tab(self.settings_form)
|
||||||
|
|
||||||
def hook_import_menu(self):
|
def hook_import_menu(self):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
|
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
|
||||||
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
from __future__ import division
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from PyQt4 import QtGui, QtCore, QtWebKit
|
from PyQt4 import QtGui, QtCore, QtWebKit
|
||||||
|
@ -327,7 +327,7 @@ class Renderer(object):
|
||||||
screen_size = self.screens.current[u'size']
|
screen_size = self.screens.current[u'size']
|
||||||
self.width = screen_size.width()
|
self.width = screen_size.width()
|
||||||
self.height = screen_size.height()
|
self.height = screen_size.height()
|
||||||
self.screen_ratio = float(self.height) / float(self.width)
|
self.screen_ratio = self.height / self.width
|
||||||
log.debug(u'_calculate default %s, %f' % (screen_size, self.screen_ratio))
|
log.debug(u'_calculate default %s, %f' % (screen_size, self.screen_ratio))
|
||||||
# 90% is start of footer
|
# 90% is start of footer
|
||||||
self.footer_start = int(self.height * 0.90)
|
self.footer_start = int(self.height * 0.90)
|
||||||
|
@ -546,15 +546,15 @@ class Renderer(object):
|
||||||
"""
|
"""
|
||||||
smallest_index = 0
|
smallest_index = 0
|
||||||
highest_index = len(html_list) - 1
|
highest_index = len(html_list) - 1
|
||||||
index = int(highest_index / 2)
|
index = highest_index // 2
|
||||||
while True:
|
while True:
|
||||||
if not self._text_fits_on_slide(previous_html + separator.join(html_list[:index + 1]).strip()):
|
if not self._text_fits_on_slide(previous_html + separator.join(html_list[:index + 1]).strip()):
|
||||||
# We know that it does not fit, so change/calculate the new index and highest_index accordingly.
|
# We know that it does not fit, so change/calculate the new index and highest_index accordingly.
|
||||||
highest_index = index
|
highest_index = index
|
||||||
index = int(index - (index - smallest_index) / 2)
|
index = index - (index - smallest_index) // 2
|
||||||
else:
|
else:
|
||||||
smallest_index = index
|
smallest_index = index
|
||||||
index = int(index + (highest_index - index) / 2)
|
index = index + (highest_index - index) // 2
|
||||||
# We found the number of words which will fit.
|
# We found the number of words which will fit.
|
||||||
if smallest_index == index or highest_index == index:
|
if smallest_index == index or highest_index == index:
|
||||||
index = smallest_index
|
index = smallest_index
|
||||||
|
@ -582,7 +582,7 @@ class Renderer(object):
|
||||||
html_list[0] = html_tags + html_list[0]
|
html_list[0] = html_tags + html_list[0]
|
||||||
smallest_index = 0
|
smallest_index = 0
|
||||||
highest_index = len(html_list) - 1
|
highest_index = len(html_list) - 1
|
||||||
index = int(highest_index / 2)
|
index = highest_index // 2
|
||||||
return previous_html, previous_raw
|
return previous_html, previous_raw
|
||||||
|
|
||||||
def _text_fits_on_slide(self, text):
|
def _text_fits_on_slide(self, text):
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
The :mod:`screen` module provides management functionality for a machines'
|
The :mod:`screen` module provides management functionality for a machines'
|
||||||
displays.
|
displays.
|
||||||
"""
|
"""
|
||||||
|
from __future__ import division
|
||||||
import logging
|
import logging
|
||||||
import copy
|
import copy
|
||||||
|
|
||||||
|
@ -232,8 +233,8 @@ class ScreenList(object):
|
||||||
``window``
|
``window``
|
||||||
A QWidget we are finding the location of.
|
A QWidget we are finding the location of.
|
||||||
"""
|
"""
|
||||||
x = window.x() + (window.width() / 2)
|
x = window.x() + (window.width() // 2)
|
||||||
y = window.y() + (window.height() / 2)
|
y = window.y() + (window.height() // 2)
|
||||||
for screen in self.screen_list:
|
for screen in self.screen_list:
|
||||||
size = screen[u'size']
|
size = screen[u'size']
|
||||||
if x >= size.x() and x <= (size.x() + size.width()) and y >= size.y() and y <= (size.y() + size.height()):
|
if x >= size.x() and x <= (size.x() + size.width()) and y >= size.y() and y <= (size.y() + size.height()):
|
||||||
|
@ -247,15 +248,15 @@ class ScreenList(object):
|
||||||
# Add the screen settings to the settings dict. This has to be done here due to cyclic dependency.
|
# Add the screen settings to the settings dict. This has to be done here due to cyclic dependency.
|
||||||
# Do not do this anywhere else.
|
# Do not do this anywhere else.
|
||||||
screen_settings = {
|
screen_settings = {
|
||||||
u'general/x position': self.current[u'size'].x(),
|
u'core/x position': self.current[u'size'].x(),
|
||||||
u'general/y position': self.current[u'size'].y(),
|
u'core/y position': self.current[u'size'].y(),
|
||||||
u'general/monitor': self.display_count - 1,
|
u'core/monitor': self.display_count - 1,
|
||||||
u'general/height': self.current[u'size'].height(),
|
u'core/height': self.current[u'size'].height(),
|
||||||
u'general/width': self.current[u'size'].width()
|
u'core/width': self.current[u'size'].width()
|
||||||
}
|
}
|
||||||
Settings.extend_default_settings(screen_settings)
|
Settings.extend_default_settings(screen_settings)
|
||||||
settings = Settings()
|
settings = Settings()
|
||||||
settings.beginGroup(u'general')
|
settings.beginGroup(u'core')
|
||||||
monitor = settings.value(u'monitor')
|
monitor = settings.value(u'monitor')
|
||||||
self.set_current_display(monitor)
|
self.set_current_display(monitor)
|
||||||
self.display = settings.value(u'display on monitor')
|
self.display = settings.value(u'display on monitor')
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
|
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
|
||||||
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
from __future__ import division
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from PyQt4 import QtCore, QtGui
|
from PyQt4 import QtCore, QtGui
|
||||||
|
@ -85,10 +85,10 @@ class SearchEdit(QtGui.QLineEdit):
|
||||||
size = self.clear_button.size()
|
size = self.clear_button.size()
|
||||||
frame_width = self.style().pixelMetric(QtGui.QStyle.PM_DefaultFrameWidth)
|
frame_width = self.style().pixelMetric(QtGui.QStyle.PM_DefaultFrameWidth)
|
||||||
self.clear_button.move(self.rect().right() - frame_width - size.width(),
|
self.clear_button.move(self.rect().right() - frame_width - size.width(),
|
||||||
(self.rect().bottom() + 1 - size.height()) / 2)
|
(self.rect().bottom() + 1 - size.height()) // 2)
|
||||||
if hasattr(self, u'menu_button'):
|
if hasattr(self, u'menu_button'):
|
||||||
size = self.menu_button.size()
|
size = self.menu_button.size()
|
||||||
self.menu_button.move(self.rect().left() + frame_width + 2, (self.rect().bottom() + 1 - size.height()) / 2)
|
self.menu_button.move(self.rect().left() + frame_width + 2, (self.rect().bottom() + 1 - size.height()) // 2)
|
||||||
|
|
||||||
def current_search_type(self):
|
def current_search_type(self):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -58,23 +58,19 @@ class ItemCapabilities(object):
|
||||||
Provides an enumeration of a service item's capabilities
|
Provides an enumeration of a service item's capabilities
|
||||||
|
|
||||||
``CanPreview``
|
``CanPreview``
|
||||||
The capability to allow the ServiceManager to add to the preview
|
The capability to allow the ServiceManager to add to the preview tab when making the previous item live.
|
||||||
tab when making the previous item live.
|
|
||||||
|
|
||||||
``CanEdit``
|
``CanEdit``
|
||||||
The capability to allow the ServiceManager to allow the item to be
|
The capability to allow the ServiceManager to allow the item to be edited
|
||||||
edited
|
|
||||||
|
|
||||||
``CanMaintain``
|
``CanMaintain``
|
||||||
The capability to allow the ServiceManager to allow the item to be
|
The capability to allow the ServiceManager to allow the item to be reordered.
|
||||||
reordered.
|
|
||||||
|
|
||||||
``RequiresMedia``
|
``RequiresMedia``
|
||||||
Determines is the service_item needs a Media Player
|
Determines is the service_item needs a Media Player
|
||||||
|
|
||||||
``CanLoop``
|
``CanLoop``
|
||||||
The capability to allow the SlideController to allow the loop
|
The capability to allow the SlideController to allow the loop processing.
|
||||||
processing.
|
|
||||||
|
|
||||||
``CanAppend``
|
``CanAppend``
|
||||||
The capability to allow the ServiceManager to add leaves to the
|
The capability to allow the ServiceManager to add leaves to the
|
||||||
|
@ -84,22 +80,19 @@ class ItemCapabilities(object):
|
||||||
The capability to remove lines breaks in the renderer
|
The capability to remove lines breaks in the renderer
|
||||||
|
|
||||||
``OnLoadUpdate``
|
``OnLoadUpdate``
|
||||||
The capability to update MediaManager when a service Item is
|
The capability to update MediaManager when a service Item is loaded.
|
||||||
loaded.
|
|
||||||
|
|
||||||
``AddIfNewItem``
|
``AddIfNewItem``
|
||||||
Not Used
|
Not Used
|
||||||
|
|
||||||
``ProvidesOwnDisplay``
|
``ProvidesOwnDisplay``
|
||||||
The capability to tell the SlideController the service Item has a
|
The capability to tell the SlideController the service Item has a different display.
|
||||||
different display.
|
|
||||||
|
|
||||||
``HasDetailedTitleDisplay``
|
``HasDetailedTitleDisplay``
|
||||||
ServiceItem provides a title
|
Being Removed and decommissioned.
|
||||||
|
|
||||||
``HasVariableStartTime``
|
``HasVariableStartTime``
|
||||||
The capability to tell the ServiceManager that a change to start
|
The capability to tell the ServiceManager that a change to start time is possible.
|
||||||
time is possible.
|
|
||||||
|
|
||||||
``CanSoftBreak``
|
``CanSoftBreak``
|
||||||
The capability to tell the renderer that Soft Break is allowed
|
The capability to tell the renderer that Soft Break is allowed
|
||||||
|
@ -151,7 +144,7 @@ class ServiceItem(object):
|
||||||
if plugin:
|
if plugin:
|
||||||
self.name = plugin.name
|
self.name = plugin.name
|
||||||
self.title = u''
|
self.title = u''
|
||||||
self.shortname = u''
|
self.processor = None
|
||||||
self.audit = u''
|
self.audit = u''
|
||||||
self.items = []
|
self.items = []
|
||||||
self.iconic_representation = None
|
self.iconic_representation = None
|
||||||
|
@ -355,7 +348,8 @@ class ServiceItem(object):
|
||||||
u'media_length': self.media_length,
|
u'media_length': self.media_length,
|
||||||
u'background_audio': self.background_audio,
|
u'background_audio': self.background_audio,
|
||||||
u'theme_overwritten': self.theme_overwritten,
|
u'theme_overwritten': self.theme_overwritten,
|
||||||
u'will_auto_start': self.will_auto_start
|
u'will_auto_start': self.will_auto_start,
|
||||||
|
u'processor': self.processor
|
||||||
}
|
}
|
||||||
service_data = []
|
service_data = []
|
||||||
if self.service_item_type == ServiceItemType.Text:
|
if self.service_item_type == ServiceItemType.Text:
|
||||||
|
@ -389,7 +383,6 @@ class ServiceItem(object):
|
||||||
self.title = header[u'title']
|
self.title = header[u'title']
|
||||||
self.name = header[u'name']
|
self.name = header[u'name']
|
||||||
self.service_item_type = header[u'type']
|
self.service_item_type = header[u'type']
|
||||||
self.shortname = header[u'plugin']
|
|
||||||
self.theme = header[u'theme']
|
self.theme = header[u'theme']
|
||||||
self.add_icon(header[u'icon'])
|
self.add_icon(header[u'icon'])
|
||||||
self.raw_footer = header[u'footer']
|
self.raw_footer = header[u'footer']
|
||||||
|
@ -408,7 +401,13 @@ class ServiceItem(object):
|
||||||
self.auto_play_slides_loop = header.get(u'auto_play_slides_loop', False)
|
self.auto_play_slides_loop = header.get(u'auto_play_slides_loop', False)
|
||||||
self.timed_slide_interval = header.get(u'timed_slide_interval', 0)
|
self.timed_slide_interval = header.get(u'timed_slide_interval', 0)
|
||||||
self.will_auto_start = header.get(u'will_auto_start', False)
|
self.will_auto_start = header.get(u'will_auto_start', False)
|
||||||
|
self.processor = header.get(u'processor', None)
|
||||||
self.has_original_files = True
|
self.has_original_files = True
|
||||||
|
#TODO Remove me in 2,3 build phase
|
||||||
|
if self.is_capable(ItemCapabilities.HasDetailedTitleDisplay):
|
||||||
|
self.capabilities.remove(ItemCapabilities.HasDetailedTitleDisplay)
|
||||||
|
self.processor = self.title
|
||||||
|
self.title = None
|
||||||
if u'background_audio' in header:
|
if u'background_audio' in header:
|
||||||
self.background_audio = []
|
self.background_audio = []
|
||||||
for filename in header[u'background_audio']:
|
for filename in header[u'background_audio']:
|
||||||
|
@ -431,6 +430,8 @@ class ServiceItem(object):
|
||||||
self.add_from_image(text_image[u'path'], text_image[u'title'], background)
|
self.add_from_image(text_image[u'path'], text_image[u'title'], background)
|
||||||
elif self.service_item_type == ServiceItemType.Command:
|
elif self.service_item_type == ServiceItemType.Command:
|
||||||
for text_image in serviceitem[u'serviceitem'][u'data']:
|
for text_image in serviceitem[u'serviceitem'][u'data']:
|
||||||
|
if not self.title:
|
||||||
|
self.title = text_image[u'title']
|
||||||
if path:
|
if path:
|
||||||
self.has_original_files = False
|
self.has_original_files = False
|
||||||
self.add_from_command(path, text_image[u'title'], text_image[u'image'])
|
self.add_from_command(path, text_image[u'title'], text_image[u'image'])
|
||||||
|
@ -445,9 +446,7 @@ class ServiceItem(object):
|
||||||
if self.is_text():
|
if self.is_text():
|
||||||
return self.title
|
return self.title
|
||||||
else:
|
else:
|
||||||
if ItemCapabilities.HasDetailedTitleDisplay in self.capabilities:
|
if len(self._raw_frames) > 1:
|
||||||
return self._raw_frames[0][u'title']
|
|
||||||
elif len(self._raw_frames) > 1:
|
|
||||||
return self.title
|
return self.title
|
||||||
else:
|
else:
|
||||||
return self._raw_frames[0][u'title']
|
return self._raw_frames[0][u'title']
|
||||||
|
|
|
@ -116,30 +116,29 @@ class Settings(QtCore.QSettings):
|
||||||
u'advanced/x11 bypass wm': X11_BYPASS_DEFAULT,
|
u'advanced/x11 bypass wm': X11_BYPASS_DEFAULT,
|
||||||
u'crashreport/last directory': u'',
|
u'crashreport/last directory': u'',
|
||||||
u'displayTags/html_tags': u'',
|
u'displayTags/html_tags': u'',
|
||||||
u'general/audio repeat list': False,
|
u'core/audio repeat list': False,
|
||||||
u'general/auto open': False,
|
u'core/auto open': False,
|
||||||
u'general/auto preview': False,
|
u'core/auto preview': False,
|
||||||
u'general/audio start paused': True,
|
u'core/audio start paused': True,
|
||||||
u'general/auto unblank': False,
|
u'core/auto unblank': False,
|
||||||
u'general/blank warning': False,
|
u'core/blank warning': False,
|
||||||
u'general/ccli number': u'',
|
u'core/ccli number': u'',
|
||||||
u'general/has run wizard': False,
|
u'core/has run wizard': False,
|
||||||
u'general/language': u'[en]',
|
u'core/language': u'[en]',
|
||||||
# This defaults to yesterday in order to force the update check to run when you've never run it before.
|
u'core/last version test': u'',
|
||||||
u'general/last version test': datetime.datetime.now().date() - datetime.timedelta(days=1),
|
u'core/loop delay': 5,
|
||||||
u'general/loop delay': 5,
|
u'core/recent files': [],
|
||||||
u'general/recent files': [],
|
u'core/save prompt': False,
|
||||||
u'general/save prompt': False,
|
u'core/screen blank': False,
|
||||||
u'general/screen blank': False,
|
u'core/show splash': True,
|
||||||
u'general/show splash': True,
|
u'core/songselect password': u'',
|
||||||
u'general/songselect password': u'',
|
u'core/songselect username': u'',
|
||||||
u'general/songselect username': u'',
|
u'core/update check': True,
|
||||||
u'general/update check': True,
|
u'core/view mode': u'default',
|
||||||
u'general/view mode': u'default',
|
|
||||||
# The other display settings (display position and dimensions) are defined in the ScreenList class due to a
|
# The other display settings (display position and dimensions) are defined in the ScreenList class due to a
|
||||||
# circular dependency.
|
# circular dependency.
|
||||||
u'general/display on monitor': True,
|
u'core/display on monitor': True,
|
||||||
u'general/override position': False,
|
u'core/override position': False,
|
||||||
u'images/background color': u'#000000',
|
u'images/background color': u'#000000',
|
||||||
u'media/players': u'webkit',
|
u'media/players': u'webkit',
|
||||||
u'media/override player': QtCore.Qt.Unchecked,
|
u'media/override player': QtCore.Qt.Unchecked,
|
||||||
|
@ -304,7 +303,7 @@ class Settings(QtCore.QSettings):
|
||||||
# Changed during 1.9.x development.
|
# Changed during 1.9.x development.
|
||||||
(u'bibles/bookname language', u'bibles/book name language', []),
|
(u'bibles/bookname language', u'bibles/book name language', []),
|
||||||
(u'general/enable slide loop', u'advanced/slide limits', [(SlideLimits.Wrap, True), (SlideLimits.End, False)]),
|
(u'general/enable slide loop', u'advanced/slide limits', [(SlideLimits.Wrap, True), (SlideLimits.End, False)]),
|
||||||
(u'songs/ccli number', u'general/ccli number', []),
|
(u'songs/ccli number', u'core/ccli number', []),
|
||||||
(u'media/use phonon', u'', []),
|
(u'media/use phonon', u'', []),
|
||||||
# Changed during 2.1.x development.
|
# Changed during 2.1.x development.
|
||||||
(u'advanced/stylesheet fix', u'', []),
|
(u'advanced/stylesheet fix', u'', []),
|
||||||
|
@ -315,7 +314,34 @@ class Settings(QtCore.QSettings):
|
||||||
(u'songs/last directory 1', u'songs/last directory import', []),
|
(u'songs/last directory 1', u'songs/last directory import', []),
|
||||||
(u'songusage/last directory 1', u'songusage/last directory export', []),
|
(u'songusage/last directory 1', u'songusage/last directory export', []),
|
||||||
(u'user interface/mainwindow splitter geometry', u'user interface/main window splitter geometry', []),
|
(u'user interface/mainwindow splitter geometry', u'user interface/main window splitter geometry', []),
|
||||||
(u'shortcuts/makeLive', u'shortcuts/make_live', [])
|
(u'shortcuts/makeLive', u'shortcuts/make_live', []),
|
||||||
|
(u'general/audio repeat list', u'core/audio repeat list', []),
|
||||||
|
(u'general/auto open', u'core/auto open', []),
|
||||||
|
(u'general/auto preview', u'core/auto preview', []),
|
||||||
|
(u'general/audio start paused', u'core/audio start paused', []),
|
||||||
|
(u'general/auto unblank', u'core/auto unblank', []),
|
||||||
|
(u'general/blank warning', u'core/blank warning', []),
|
||||||
|
(u'general/ccli number', u'core/ccli number', []),
|
||||||
|
(u'general/has run wizard', u'core/has run wizard', []),
|
||||||
|
(u'general/language', u'core/language', []),
|
||||||
|
(u'general/last version test', u'core/last version test', []),
|
||||||
|
(u'general/loop delay', u'core/loop delay', []),
|
||||||
|
(u'general/recent files', u'core/recent files', []),
|
||||||
|
(u'general/save prompt', u'core/save prompt', []),
|
||||||
|
(u'general/screen blank', u'core/screen blank', []),
|
||||||
|
(u'general/show splash', u'core/show splash', []),
|
||||||
|
(u'general/songselect password', u'core/songselect password', []),
|
||||||
|
(u'general/songselect username', u'core/songselect username', []),
|
||||||
|
(u'general/update check', u'core/update check', []),
|
||||||
|
(u'general/view mode', u'core/view mode', []),
|
||||||
|
(u'general/display on monitor', u'core/display on monitor', []),
|
||||||
|
(u'general/override position', u'core/override position', []),
|
||||||
|
(u'general/x position', u'core/x position', []),
|
||||||
|
(u'general/y position', u'core/y position', []),
|
||||||
|
(u'general/monitor', u'core/monitor', []),
|
||||||
|
(u'general/height', u'core/height', []),
|
||||||
|
(u'general/monitor', u'core/monitor', []),
|
||||||
|
(u'general/width', u'core/width', [])
|
||||||
]
|
]
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
The :mod:`~openlp.core.lib.settingstab` module contains the base SettingsTab class which plugins use for adding their
|
The :mod:`~openlp.core.lib.settingstab` module contains the base SettingsTab class which plugins use for adding their
|
||||||
own tab to the settings dialog.
|
own tab to the settings dialog.
|
||||||
"""
|
"""
|
||||||
|
from __future__ import division
|
||||||
|
|
||||||
from PyQt4 import QtGui
|
from PyQt4 import QtGui
|
||||||
|
|
||||||
|
@ -90,7 +91,7 @@ class SettingsTab(QtGui.QWidget):
|
||||||
QtGui.QWidget.resizeEvent(self, event)
|
QtGui.QWidget.resizeEvent(self, event)
|
||||||
width = self.width() - self.tab_layout.spacing() - \
|
width = self.width() - self.tab_layout.spacing() - \
|
||||||
self.tab_layout.contentsMargins().left() - self.tab_layout.contentsMargins().right()
|
self.tab_layout.contentsMargins().left() - self.tab_layout.contentsMargins().right()
|
||||||
left_width = min(width - self.right_column.minimumSizeHint().width(), width / 2)
|
left_width = min(width - self.right_column.minimumSizeHint().width(), width // 2)
|
||||||
left_width = max(left_width, self.left_column.minimumSizeHint().width())
|
left_width = max(left_width, self.left_column.minimumSizeHint().width())
|
||||||
self.left_column.setFixedWidth(left_width)
|
self.left_column.setFixedWidth(left_width)
|
||||||
|
|
||||||
|
|
|
@ -107,7 +107,6 @@ class UiStrings(object):
|
||||||
self.NFSp = translate('OpenLP.Ui', 'No Files Selected', 'Plural')
|
self.NFSp = translate('OpenLP.Ui', 'No Files Selected', 'Plural')
|
||||||
self.NISs = translate('OpenLP.Ui', 'No Item Selected', 'Singular')
|
self.NISs = translate('OpenLP.Ui', 'No Item Selected', 'Singular')
|
||||||
self.NISp = translate('OpenLP.Ui', 'No Items Selected', 'Plural')
|
self.NISp = translate('OpenLP.Ui', 'No Items Selected', 'Plural')
|
||||||
self.OLPV1 = translate('OpenLP.Ui', 'openlp.org 1.x')
|
|
||||||
self.OLPV2 = translate('OpenLP.Ui', 'OpenLP 2')
|
self.OLPV2 = translate('OpenLP.Ui', 'OpenLP 2')
|
||||||
self.OLPV2x = translate('OpenLP.Ui', 'OpenLP 2.1')
|
self.OLPV2x = translate('OpenLP.Ui', 'OpenLP 2.1')
|
||||||
self.OpenLPStart = translate('OpenLP.Ui', 'OpenLP is already running. Do you wish to continue?')
|
self.OpenLPStart = translate('OpenLP.Ui', 'OpenLP is already running. Do you wish to continue?')
|
||||||
|
|
|
@ -35,7 +35,7 @@ import os
|
||||||
import platform
|
import platform
|
||||||
|
|
||||||
import sqlalchemy
|
import sqlalchemy
|
||||||
import BeautifulSoup
|
from bs4 import BeautifulSoup
|
||||||
from lxml import etree
|
from lxml import etree
|
||||||
from PyQt4 import Qt, QtCore, QtGui, QtWebKit
|
from PyQt4 import Qt, QtCore, QtGui, QtWebKit
|
||||||
|
|
||||||
|
@ -59,11 +59,6 @@ try:
|
||||||
ENCHANT_VERSION = enchant.__version__
|
ENCHANT_VERSION = enchant.__version__
|
||||||
except ImportError:
|
except ImportError:
|
||||||
ENCHANT_VERSION = u'-'
|
ENCHANT_VERSION = u'-'
|
||||||
try:
|
|
||||||
import sqlite
|
|
||||||
SQLITE_VERSION = sqlite.version
|
|
||||||
except ImportError:
|
|
||||||
SQLITE_VERSION = u'-'
|
|
||||||
try:
|
try:
|
||||||
import mako
|
import mako
|
||||||
MAKO_VERSION = mako.__version__
|
MAKO_VERSION = mako.__version__
|
||||||
|
@ -72,11 +67,16 @@ except ImportError:
|
||||||
try:
|
try:
|
||||||
import icu
|
import icu
|
||||||
try:
|
try:
|
||||||
ICU_VERSION = icu.VERSION
|
ICU_VERSION = icu.VERSION
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
ICU_VERSION = u'OK'
|
ICU_VERSION = u'OK'
|
||||||
except ImportError:
|
except ImportError:
|
||||||
ICU_VERSION = u'-'
|
ICU_VERSION = u'-'
|
||||||
|
try:
|
||||||
|
import cherrypy
|
||||||
|
CHERRYPY_VERSION = cherrypy.__version__
|
||||||
|
except ImportError:
|
||||||
|
CHERRYPY_VERSION = u'-'
|
||||||
try:
|
try:
|
||||||
import uno
|
import uno
|
||||||
arg = uno.createUnoStruct(u'com.sun.star.beans.PropertyValue')
|
arg = uno.createUnoStruct(u'com.sun.star.beans.PropertyValue')
|
||||||
|
@ -149,8 +149,8 @@ class ExceptionForm(QtGui.QDialog, Ui_ExceptionDialog):
|
||||||
u'lxml: %s\n' % etree.__version__ + \
|
u'lxml: %s\n' % etree.__version__ + \
|
||||||
u'Chardet: %s\n' % CHARDET_VERSION + \
|
u'Chardet: %s\n' % CHARDET_VERSION + \
|
||||||
u'PyEnchant: %s\n' % ENCHANT_VERSION + \
|
u'PyEnchant: %s\n' % ENCHANT_VERSION + \
|
||||||
u'PySQLite: %s\n' % SQLITE_VERSION + \
|
|
||||||
u'Mako: %s\n' % MAKO_VERSION + \
|
u'Mako: %s\n' % MAKO_VERSION + \
|
||||||
|
u'CherryPy: %s\n' % CHERRYPY_VERSION + \
|
||||||
u'pyICU: %s\n' % ICU_VERSION + \
|
u'pyICU: %s\n' % ICU_VERSION + \
|
||||||
u'pyUNO bridge: %s\n' % UNO_VERSION + \
|
u'pyUNO bridge: %s\n' % UNO_VERSION + \
|
||||||
u'VLC: %s\n' % VLC_VERSION
|
u'VLC: %s\n' % VLC_VERSION
|
||||||
|
|
|
@ -118,7 +118,7 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
|
||||||
check_directory_exists(os.path.join(unicode(gettempdir(), get_filesystem_encoding()), u'openlp'))
|
check_directory_exists(os.path.join(unicode(gettempdir(), get_filesystem_encoding()), u'openlp'))
|
||||||
self.noInternetFinishButton.setVisible(False)
|
self.noInternetFinishButton.setVisible(False)
|
||||||
# Check if this is a re-run of the wizard.
|
# Check if this is a re-run of the wizard.
|
||||||
self.hasRunWizard = Settings().value(u'general/has run wizard')
|
self.hasRunWizard = Settings().value(u'core/has run wizard')
|
||||||
# Sort out internet access for downloads
|
# Sort out internet access for downloads
|
||||||
if self.web_access:
|
if self.web_access:
|
||||||
songs = self.config.get(u'songs', u'languages')
|
songs = self.config.get(u'songs', u'languages')
|
||||||
|
@ -252,7 +252,7 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
|
||||||
self.application.set_busy_cursor()
|
self.application.set_busy_cursor()
|
||||||
self._performWizard()
|
self._performWizard()
|
||||||
self.application.set_normal_cursor()
|
self.application.set_normal_cursor()
|
||||||
Settings().setValue(u'general/has run wizard', True)
|
Settings().setValue(u'core/has run wizard', True)
|
||||||
self.close()
|
self.close()
|
||||||
|
|
||||||
def urlGetFile(self, url, fpath):
|
def urlGetFile(self, url, fpath):
|
||||||
|
@ -459,7 +459,7 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
|
||||||
self.urlGetFile(u'%s%s' % (self.web, theme), os.path.join(themes_destination, theme))
|
self.urlGetFile(u'%s%s' % (self.web, theme), os.path.join(themes_destination, theme))
|
||||||
# Set Default Display
|
# Set Default Display
|
||||||
if self.displayComboBox.currentIndex() != -1:
|
if self.displayComboBox.currentIndex() != -1:
|
||||||
Settings().setValue(u'General/monitor', self.displayComboBox.currentIndex())
|
Settings().setValue(u'core/monitor', self.displayComboBox.currentIndex())
|
||||||
self.screens.set_current_display(self.displayComboBox.currentIndex())
|
self.screens.set_current_display(self.displayComboBox.currentIndex())
|
||||||
# Set Global Theme
|
# Set Global Theme
|
||||||
if self.themeComboBox.currentIndex() != -1:
|
if self.themeComboBox.currentIndex() != -1:
|
||||||
|
|
|
@ -39,39 +39,39 @@ class Ui_FirstTimeLanguageDialog(object):
|
||||||
"""
|
"""
|
||||||
The UI widgets of the language selection dialog.
|
The UI widgets of the language selection dialog.
|
||||||
"""
|
"""
|
||||||
def setupUi(self, languageDialog):
|
def setupUi(self, language_dialog):
|
||||||
"""
|
"""
|
||||||
Set up the UI.
|
Set up the UI.
|
||||||
"""
|
"""
|
||||||
languageDialog.setObjectName(u'languageDialog')
|
language_dialog.setObjectName(u'language_dialog')
|
||||||
languageDialog.resize(300, 50)
|
language_dialog.resize(300, 50)
|
||||||
self.dialogLayout = QtGui.QVBoxLayout(languageDialog)
|
self.dialog_layout = QtGui.QVBoxLayout(language_dialog)
|
||||||
self.dialogLayout.setContentsMargins(8, 8, 8, 8)
|
self.dialog_layout.setContentsMargins(8, 8, 8, 8)
|
||||||
self.dialogLayout.setSpacing(8)
|
self.dialog_layout.setSpacing(8)
|
||||||
self.dialogLayout.setObjectName(u'dialog_layout')
|
self.dialog_layout.setObjectName(u'dialog_layout')
|
||||||
self.infoLabel = QtGui.QLabel(languageDialog)
|
self.info_label = QtGui.QLabel(language_dialog)
|
||||||
self.infoLabel.setObjectName(u'infoLabel')
|
self.info_label.setObjectName(u'info_label')
|
||||||
self.dialogLayout.addWidget(self.infoLabel)
|
self.dialog_layout.addWidget(self.info_label)
|
||||||
self.languageLayout = QtGui.QHBoxLayout()
|
self.language_layout = QtGui.QHBoxLayout()
|
||||||
self.languageLayout.setObjectName(u'languageLayout')
|
self.language_layout.setObjectName(u'language_layout')
|
||||||
self.languageLabel = QtGui.QLabel(languageDialog)
|
self.language_label = QtGui.QLabel(language_dialog)
|
||||||
self.languageLabel.setObjectName(u'languageLabel')
|
self.language_label.setObjectName(u'language_label')
|
||||||
self.languageLayout.addWidget(self.languageLabel)
|
self.language_layout.addWidget(self.language_label)
|
||||||
self.languageComboBox = QtGui.QComboBox(languageDialog)
|
self.language_combo_box = QtGui.QComboBox(language_dialog)
|
||||||
self.languageComboBox.setSizeAdjustPolicy(QtGui.QComboBox.AdjustToContents)
|
self.language_combo_box.setSizeAdjustPolicy(QtGui.QComboBox.AdjustToContents)
|
||||||
self.languageComboBox.setObjectName("languageComboBox")
|
self.language_combo_box.setObjectName("language_combo_box")
|
||||||
self.languageLayout.addWidget(self.languageComboBox)
|
self.language_layout.addWidget(self.language_combo_box)
|
||||||
self.dialogLayout.addLayout(self.languageLayout)
|
self.dialog_layout.addLayout(self.language_layout)
|
||||||
self.button_box = create_button_box(languageDialog, u'button_box', [u'cancel', u'ok'])
|
self.button_box = create_button_box(language_dialog, u'button_box', [u'cancel', u'ok'])
|
||||||
self.dialogLayout.addWidget(self.button_box)
|
self.dialog_layout.addWidget(self.button_box)
|
||||||
self.retranslateUi(languageDialog)
|
self.retranslateUi(language_dialog)
|
||||||
self.setMaximumHeight(self.sizeHint().height())
|
self.setMaximumHeight(self.sizeHint().height())
|
||||||
|
|
||||||
def retranslateUi(self, languageDialog):
|
def retranslateUi(self, language_dialog):
|
||||||
"""
|
"""
|
||||||
Translate the UI on the fly.
|
Translate the UI on the fly.
|
||||||
"""
|
"""
|
||||||
self.setWindowTitle(translate('OpenLP.FirstTimeLanguageForm', 'Select Translation'))
|
self.setWindowTitle(translate('OpenLP.FirstTimeLanguageForm', 'Select Translation'))
|
||||||
self.infoLabel.setText(
|
self.info_label.setText(
|
||||||
translate('OpenLP.FirstTimeLanguageForm', 'Choose the translation you\'d like to use in OpenLP.'))
|
translate('OpenLP.FirstTimeLanguageForm', 'Choose the translation you\'d like to use in OpenLP.'))
|
||||||
self.languageLabel.setText(translate('OpenLP.FirstTimeLanguageForm', 'Translation:'))
|
self.language_label.setText(translate('OpenLP.FirstTimeLanguageForm', 'Translation:'))
|
||||||
|
|
|
@ -47,8 +47,8 @@ class FirstTimeLanguageForm(QtGui.QDialog, Ui_FirstTimeLanguageDialog):
|
||||||
QtGui.QDialog.__init__(self, parent)
|
QtGui.QDialog.__init__(self, parent)
|
||||||
self.setupUi(self)
|
self.setupUi(self)
|
||||||
self.qmList = LanguageManager.get_qm_list()
|
self.qmList = LanguageManager.get_qm_list()
|
||||||
self.languageComboBox.addItem(u'Autodetect')
|
self.language_combo_box.addItem(u'Autodetect')
|
||||||
self.languageComboBox.addItems(sorted(self.qmList.keys()))
|
self.language_combo_box.addItems(sorted(self.qmList.keys()))
|
||||||
|
|
||||||
def exec_(self):
|
def exec_(self):
|
||||||
"""
|
"""
|
||||||
|
@ -61,12 +61,12 @@ class FirstTimeLanguageForm(QtGui.QDialog, Ui_FirstTimeLanguageDialog):
|
||||||
Run when the dialog is OKed.
|
Run when the dialog is OKed.
|
||||||
"""
|
"""
|
||||||
# It's the first row so must be Automatic
|
# It's the first row so must be Automatic
|
||||||
if self.languageComboBox.currentIndex() == 0:
|
if self.language_combo_box.currentIndex() == 0:
|
||||||
LanguageManager.auto_language = True
|
LanguageManager.auto_language = True
|
||||||
LanguageManager.set_language(False, False)
|
LanguageManager.set_language(False, False)
|
||||||
else:
|
else:
|
||||||
LanguageManager.auto_language = False
|
LanguageManager.auto_language = False
|
||||||
action = create_action(None, self.languageComboBox.currentText())
|
action = create_action(None, self.language_combo_box.currentText())
|
||||||
LanguageManager.set_language(action, False)
|
LanguageManager.set_language(action, False)
|
||||||
return QtGui.QDialog.accept(self)
|
return QtGui.QDialog.accept(self)
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,7 @@ class GeneralTab(SettingsTab):
|
||||||
self.screens = ScreenList()
|
self.screens = ScreenList()
|
||||||
self.icon_path = u':/icon/openlp-logo-16x16.png'
|
self.icon_path = u':/icon/openlp-logo-16x16.png'
|
||||||
general_translated = translate('OpenLP.GeneralTab', 'General')
|
general_translated = translate('OpenLP.GeneralTab', 'General')
|
||||||
SettingsTab.__init__(self, parent, u'General', general_translated)
|
SettingsTab.__init__(self, parent, u'Core', general_translated)
|
||||||
|
|
||||||
def setupUi(self):
|
def setupUi(self):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -35,6 +35,7 @@ Some of the code for this form is based on the examples at:
|
||||||
* `http://html5demos.com/two-videos`_
|
* `http://html5demos.com/two-videos`_
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
from __future__ import division
|
||||||
import cgi
|
import cgi
|
||||||
import logging
|
import logging
|
||||||
import sys
|
import sys
|
||||||
|
@ -207,8 +208,8 @@ class MainDisplay(Display):
|
||||||
painter_image.begin(self.initial_fame)
|
painter_image.begin(self.initial_fame)
|
||||||
painter_image.fillRect(self.initial_fame.rect(), background_color)
|
painter_image.fillRect(self.initial_fame.rect(), background_color)
|
||||||
painter_image.drawImage(
|
painter_image.drawImage(
|
||||||
(self.screen[u'size'].width() - splash_image.width()) / 2,
|
(self.screen[u'size'].width() - splash_image.width()) // 2,
|
||||||
(self.screen[u'size'].height() - splash_image.height()) / 2,
|
(self.screen[u'size'].height() - splash_image.height()) // 2,
|
||||||
splash_image)
|
splash_image)
|
||||||
service_item = ServiceItem()
|
service_item = ServiceItem()
|
||||||
service_item.bg_image_bytes = image_to_byte(self.initial_fame)
|
service_item.bg_image_bytes = image_to_byte(self.initial_fame)
|
||||||
|
@ -268,7 +269,7 @@ class MainDisplay(Display):
|
||||||
self.resize(self.width(), alert_height)
|
self.resize(self.width(), alert_height)
|
||||||
self.setVisible(True)
|
self.setVisible(True)
|
||||||
if location == AlertLocation.Middle:
|
if location == AlertLocation.Middle:
|
||||||
self.move(self.screen[u'size'].left(), (self.screen[u'size'].height() - alert_height) / 2)
|
self.move(self.screen[u'size'].left(), (self.screen[u'size'].height() - alert_height) // 2)
|
||||||
elif location == AlertLocation.Bottom:
|
elif location == AlertLocation.Bottom:
|
||||||
self.move(self.screen[u'size'].left(), self.screen[u'size'].height() - alert_height)
|
self.move(self.screen[u'size'].left(), self.screen[u'size'].height() - alert_height)
|
||||||
else:
|
else:
|
||||||
|
@ -357,7 +358,7 @@ class MainDisplay(Display):
|
||||||
# Single screen active
|
# Single screen active
|
||||||
if self.screens.display_count == 1:
|
if self.screens.display_count == 1:
|
||||||
# Only make visible if setting enabled.
|
# Only make visible if setting enabled.
|
||||||
if Settings().value(u'general/display on monitor'):
|
if Settings().value(u'core/display on monitor'):
|
||||||
self.setVisible(True)
|
self.setVisible(True)
|
||||||
else:
|
else:
|
||||||
self.setVisible(True)
|
self.setVisible(True)
|
||||||
|
@ -405,7 +406,7 @@ class MainDisplay(Display):
|
||||||
self.footer(service_item.foot_text)
|
self.footer(service_item.foot_text)
|
||||||
# if was hidden keep it hidden
|
# if was hidden keep it hidden
|
||||||
if self.hide_mode and self.is_live and not service_item.is_media():
|
if self.hide_mode and self.is_live and not service_item.is_media():
|
||||||
if Settings().value(u'general/auto unblank'):
|
if Settings().value(u'core/auto unblank'):
|
||||||
Registry().execute(u'slidecontroller_live_unblank')
|
Registry().execute(u'slidecontroller_live_unblank')
|
||||||
else:
|
else:
|
||||||
self.hide_display(self.hide_mode)
|
self.hide_display(self.hide_mode)
|
||||||
|
@ -427,7 +428,7 @@ class MainDisplay(Display):
|
||||||
log.debug(u'hide_display mode = %d', mode)
|
log.debug(u'hide_display mode = %d', mode)
|
||||||
if self.screens.display_count == 1:
|
if self.screens.display_count == 1:
|
||||||
# Only make visible if setting enabled.
|
# Only make visible if setting enabled.
|
||||||
if not Settings().value(u'general/display on monitor'):
|
if not Settings().value(u'core/display on monitor'):
|
||||||
return
|
return
|
||||||
if mode == HideMode.Screen:
|
if mode == HideMode.Screen:
|
||||||
self.frame.evaluateJavaScript(u'show_blank("desktop");')
|
self.frame.evaluateJavaScript(u'show_blank("desktop");')
|
||||||
|
@ -450,7 +451,7 @@ class MainDisplay(Display):
|
||||||
log.debug(u'show_display')
|
log.debug(u'show_display')
|
||||||
if self.screens.display_count == 1:
|
if self.screens.display_count == 1:
|
||||||
# Only make visible if setting enabled.
|
# Only make visible if setting enabled.
|
||||||
if not Settings().value(u'general/display on monitor'):
|
if not Settings().value(u'core/display on monitor'):
|
||||||
return
|
return
|
||||||
self.frame.evaluateJavaScript('show_blank("show");')
|
self.frame.evaluateJavaScript('show_blank("show");')
|
||||||
if self.isHidden():
|
if self.isHidden():
|
||||||
|
|
|
@ -476,7 +476,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
|
||||||
self.arguments = self.application.args
|
self.arguments = self.application.args
|
||||||
# Set up settings sections for the main application (not for use by plugins).
|
# Set up settings sections for the main application (not for use by plugins).
|
||||||
self.ui_settings_section = u'user interface'
|
self.ui_settings_section = u'user interface'
|
||||||
self.general_settings_section = u'general'
|
self.general_settings_section = u'core'
|
||||||
self.advanced_settings_section = u'advanced'
|
self.advanced_settings_section = u'advanced'
|
||||||
self.shortcuts_settings_section = u'shortcuts'
|
self.shortcuts_settings_section = u'shortcuts'
|
||||||
self.service_manager_settings_section = u'servicemanager'
|
self.service_manager_settings_section = u'servicemanager'
|
||||||
|
@ -491,7 +491,6 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
|
||||||
self.new_data_path = None
|
self.new_data_path = None
|
||||||
self.copy_data = False
|
self.copy_data = False
|
||||||
Settings().set_up_default_values()
|
Settings().set_up_default_values()
|
||||||
Settings().remove_obsolete_settings()
|
|
||||||
self.service_not_saved = False
|
self.service_not_saved = False
|
||||||
self.about_form = AboutForm(self)
|
self.about_form = AboutForm(self)
|
||||||
self.media_controller = MediaController()
|
self.media_controller = MediaController()
|
||||||
|
@ -560,7 +559,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
|
||||||
"""
|
"""
|
||||||
widget = self.media_tool_box.widget(index)
|
widget = self.media_tool_box.widget(index)
|
||||||
if widget:
|
if widget:
|
||||||
widget.onFocus()
|
widget.on_focus()
|
||||||
|
|
||||||
def version_notice(self, version):
|
def version_notice(self, version):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -415,7 +415,7 @@ class MediaController(object):
|
||||||
elif not hidden or controller.media_info.is_background or service_item.will_auto_start:
|
elif not hidden or controller.media_info.is_background or service_item.will_auto_start:
|
||||||
autoplay = True
|
autoplay = True
|
||||||
# Unblank on load set
|
# Unblank on load set
|
||||||
elif Settings().value(u'general/auto unblank'):
|
elif Settings().value(u'core/auto unblank'):
|
||||||
autoplay = True
|
autoplay = True
|
||||||
if autoplay:
|
if autoplay:
|
||||||
if not self.media_play(controller):
|
if not self.media_play(controller):
|
||||||
|
@ -466,8 +466,8 @@ class MediaController(object):
|
||||||
The ServiceItem containing the details to be played.
|
The ServiceItem containing the details to be played.
|
||||||
"""
|
"""
|
||||||
used_players = get_media_players()[0]
|
used_players = get_media_players()[0]
|
||||||
if service_item.title != UiStrings().Automatic:
|
if service_item.processor != UiStrings().Automatic:
|
||||||
used_players = [service_item.title.lower()]
|
used_players = [service_item.processor.lower()]
|
||||||
if controller.media_info.file_info.isFile():
|
if controller.media_info.file_info.isFile():
|
||||||
suffix = u'*.%s' % controller.media_info.file_info.suffix().lower()
|
suffix = u'*.%s' % controller.media_info.file_info.suffix().lower()
|
||||||
for title in used_players:
|
for title in used_players:
|
||||||
|
|
|
@ -273,7 +273,6 @@ class ServiceManagerDialog(object):
|
||||||
Registry().register_function(u'config_screen_changed', self.regenerate_service_Items)
|
Registry().register_function(u'config_screen_changed', self.regenerate_service_Items)
|
||||||
Registry().register_function(u'theme_update_global', self.theme_change)
|
Registry().register_function(u'theme_update_global', self.theme_change)
|
||||||
Registry().register_function(u'mediaitem_suffix_reset', self.reset_supported_suffixes)
|
Registry().register_function(u'mediaitem_suffix_reset', self.reset_supported_suffixes)
|
||||||
Registry().register_function(u'servicemanager_set_item', self.on_set_item)
|
|
||||||
|
|
||||||
def drag_enter_event(self, event):
|
def drag_enter_event(self, event):
|
||||||
"""
|
"""
|
||||||
|
@ -296,8 +295,8 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
||||||
Sets up the service manager, toolbars, list view, et al.
|
Sets up the service manager, toolbars, list view, et al.
|
||||||
"""
|
"""
|
||||||
QtGui.QWidget.__init__(self, parent)
|
QtGui.QWidget.__init__(self, parent)
|
||||||
self.active = build_icon(QtGui.QImage(u':/media/auto-start_active.png'))
|
self.active = build_icon(u':/media/auto-start_active.png')
|
||||||
self.inactive = build_icon(QtGui.QImage(u':/media/auto-start_inactive.png'))
|
self.inactive = build_icon(u':/media/auto-start_inactive.png')
|
||||||
Registry().register(u'service_manager', self)
|
Registry().register(u'service_manager', self)
|
||||||
self.service_items = []
|
self.service_items = []
|
||||||
self.suffixes = []
|
self.suffixes = []
|
||||||
|
@ -315,6 +314,8 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
||||||
self.layout.setSpacing(0)
|
self.layout.setSpacing(0)
|
||||||
self.layout.setMargin(0)
|
self.layout.setMargin(0)
|
||||||
self.setup_ui(self)
|
self.setup_ui(self)
|
||||||
|
# Need to use event as called across threads and UI is updated
|
||||||
|
QtCore.QObject.connect(self, QtCore.SIGNAL(u'servicemanager_set_item'), self.on_set_item)
|
||||||
|
|
||||||
def set_modified(self, modified=True):
|
def set_modified(self, modified=True):
|
||||||
"""
|
"""
|
||||||
|
@ -714,13 +715,10 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
||||||
else:
|
else:
|
||||||
service_item.set_from_service(item, self.servicePath)
|
service_item.set_from_service(item, self.servicePath)
|
||||||
service_item.validate_item(self.suffixes)
|
service_item.validate_item(self.suffixes)
|
||||||
self.load_item_unique_identifier = 0
|
|
||||||
if service_item.is_capable(ItemCapabilities.OnLoadUpdate):
|
if service_item.is_capable(ItemCapabilities.OnLoadUpdate):
|
||||||
Registry().execute(u'%s_service_load' % service_item.name.lower(), service_item)
|
new_item = Registry().get(service_item.name).service_load(service_item)
|
||||||
# if the item has been processed
|
if new_item:
|
||||||
if service_item.unique_identifier == self.load_item_unique_identifier:
|
service_item = new_item
|
||||||
service_item.edit_id = int(self.load_item_edit_id)
|
|
||||||
service_item.temporary_edit = self.load_item_temporary
|
|
||||||
self.add_service_item(service_item, repaint=False)
|
self.add_service_item(service_item, repaint=False)
|
||||||
delete_file(p_file)
|
delete_file(p_file)
|
||||||
self.main_window.add_recent_file(file_name)
|
self.main_window.add_recent_file(file_name)
|
||||||
|
@ -993,7 +991,7 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
||||||
|
|
||||||
def on_set_item(self, message):
|
def on_set_item(self, message):
|
||||||
"""
|
"""
|
||||||
Called by a signal to select a specific item.
|
Called by a signal to select a specific item and make it live usually from remote.
|
||||||
"""
|
"""
|
||||||
self.set_item(int(message))
|
self.set_item(int(message))
|
||||||
|
|
||||||
|
@ -1259,14 +1257,6 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
||||||
self.repaint_service_list(-1, -1)
|
self.repaint_service_list(-1, -1)
|
||||||
self.application.set_normal_cursor()
|
self.application.set_normal_cursor()
|
||||||
|
|
||||||
def service_item_update(self, edit_id, unique_identifier, temporary=False):
|
|
||||||
"""
|
|
||||||
Triggered from plugins to update service items. Save the values as they will be used as part of the service load
|
|
||||||
"""
|
|
||||||
self.load_item_unique_identifier = unique_identifier
|
|
||||||
self.load_item_edit_id = int(edit_id)
|
|
||||||
self.load_item_temporary = str_to_bool(temporary)
|
|
||||||
|
|
||||||
def replace_service_item(self, newItem):
|
def replace_service_item(self, newItem):
|
||||||
"""
|
"""
|
||||||
Using the service item passed replace the one with the same edit id if found.
|
Using the service item passed replace the one with the same edit id if found.
|
||||||
|
@ -1393,7 +1383,7 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
||||||
item = self.find_service_item()[0]
|
item = self.find_service_item()[0]
|
||||||
if self.service_items[item][u'service_item'].is_capable(ItemCapabilities.CanEdit):
|
if self.service_items[item][u'service_item'].is_capable(ItemCapabilities.CanEdit):
|
||||||
new_item = Registry().get(self.service_items[item][u'service_item'].name). \
|
new_item = Registry().get(self.service_items[item][u'service_item'].name). \
|
||||||
onRemoteEdit(self.service_items[item][u'service_item'].edit_id)
|
on_remote_edit(self.service_items[item][u'service_item'].edit_id)
|
||||||
if new_item:
|
if new_item:
|
||||||
self.add_service_item(new_item, replace=True)
|
self.add_service_item(new_item, replace=True)
|
||||||
|
|
||||||
|
|
|
@ -96,6 +96,7 @@ class SettingsForm(QtGui.QDialog, Ui_SettingsDialog):
|
||||||
"""
|
"""
|
||||||
Process the form saving the settings
|
Process the form saving the settings
|
||||||
"""
|
"""
|
||||||
|
log.debug(u'Processing settings exit')
|
||||||
for tabIndex in range(self.stacked_layout.count()):
|
for tabIndex in range(self.stacked_layout.count()):
|
||||||
self.stacked_layout.widget(tabIndex).save()
|
self.stacked_layout.widget(tabIndex).save()
|
||||||
# if the display of image background are changing we need to regenerate the image cache
|
# if the display of image background are changing we need to regenerate the image cache
|
||||||
|
|
|
@ -360,8 +360,9 @@ class SlideController(DisplayController):
|
||||||
# Signals
|
# Signals
|
||||||
self.preview_list_widget.clicked.connect(self.onSlideSelected)
|
self.preview_list_widget.clicked.connect(self.onSlideSelected)
|
||||||
if self.is_live:
|
if self.is_live:
|
||||||
|
# Need to use event as called across threads and UI is updated
|
||||||
|
QtCore.QObject.connect(self, QtCore.SIGNAL(u'slidecontroller_toggle_display'), self.toggle_display)
|
||||||
Registry().register_function(u'slidecontroller_live_spin_delay', self.receive_spin_delay)
|
Registry().register_function(u'slidecontroller_live_spin_delay', self.receive_spin_delay)
|
||||||
Registry().register_function(u'slidecontroller_toggle_display', self.toggle_display)
|
|
||||||
self.toolbar.set_widget_visible(self.loop_list, False)
|
self.toolbar.set_widget_visible(self.loop_list, False)
|
||||||
self.toolbar.set_widget_visible(self.wide_menu, False)
|
self.toolbar.set_widget_visible(self.wide_menu, False)
|
||||||
else:
|
else:
|
||||||
|
@ -373,13 +374,16 @@ class SlideController(DisplayController):
|
||||||
else:
|
else:
|
||||||
self.preview_list_widget.addActions([self.nextItem, self.previous_item])
|
self.preview_list_widget.addActions([self.nextItem, self.previous_item])
|
||||||
Registry().register_function(u'slidecontroller_%s_stop_loop' % self.type_prefix, self.on_stop_loop)
|
Registry().register_function(u'slidecontroller_%s_stop_loop' % self.type_prefix, self.on_stop_loop)
|
||||||
Registry().register_function(u'slidecontroller_%s_next' % self.type_prefix, self.on_slide_selected_next)
|
|
||||||
Registry().register_function(u'slidecontroller_%s_previous' % self.type_prefix, self.on_slide_selected_previous)
|
|
||||||
Registry().register_function(u'slidecontroller_%s_change' % self.type_prefix, self.on_slide_change)
|
Registry().register_function(u'slidecontroller_%s_change' % self.type_prefix, self.on_slide_change)
|
||||||
Registry().register_function(u'slidecontroller_%s_set' % self.type_prefix, self.on_slide_selected_index)
|
|
||||||
Registry().register_function(u'slidecontroller_%s_blank' % self.type_prefix, self.on_slide_blank)
|
Registry().register_function(u'slidecontroller_%s_blank' % self.type_prefix, self.on_slide_blank)
|
||||||
Registry().register_function(u'slidecontroller_%s_unblank' % self.type_prefix, self.on_slide_unblank)
|
Registry().register_function(u'slidecontroller_%s_unblank' % self.type_prefix, self.on_slide_unblank)
|
||||||
Registry().register_function(u'slidecontroller_update_slide_limits', self.update_slide_limits)
|
Registry().register_function(u'slidecontroller_update_slide_limits', self.update_slide_limits)
|
||||||
|
QtCore.QObject.connect(self, QtCore.SIGNAL(u'slidecontroller_%s_set' % self.type_prefix),
|
||||||
|
self.on_slide_selected_index)
|
||||||
|
QtCore.QObject.connect(self, QtCore.SIGNAL(u'slidecontroller_%s_next' % self.type_prefix),
|
||||||
|
self.on_slide_selected_next)
|
||||||
|
QtCore.QObject.connect(self, QtCore.SIGNAL(u'slidecontroller_%s_previous' % self.type_prefix),
|
||||||
|
self.on_slide_selected_previous)
|
||||||
|
|
||||||
def _slideShortcutActivated(self):
|
def _slideShortcutActivated(self):
|
||||||
"""
|
"""
|
||||||
|
@ -612,7 +616,7 @@ class SlideController(DisplayController):
|
||||||
"""
|
"""
|
||||||
Adjusts the value of the ``delay_spin_box`` to the given one.
|
Adjusts the value of the ``delay_spin_box`` to the given one.
|
||||||
"""
|
"""
|
||||||
self.delay_spin_box.setValue(Settings().value(u'general/loop delay'))
|
self.delay_spin_box.setValue(Settings().value(u'core/loop delay'))
|
||||||
|
|
||||||
def update_slide_limits(self):
|
def update_slide_limits(self):
|
||||||
"""
|
"""
|
||||||
|
@ -1229,7 +1233,7 @@ class SlideController(DisplayController):
|
||||||
From the preview display requires the service Item to be editied
|
From the preview display requires the service Item to be editied
|
||||||
"""
|
"""
|
||||||
self.song_edit = True
|
self.song_edit = True
|
||||||
new_item = Registry().get(self.service_item.name).onRemoteEdit(self.service_item.edit_id, True)
|
new_item = Registry().get(self.service_item.name).on_remote_edit(self.service_item.edit_id, True)
|
||||||
if new_item:
|
if new_item:
|
||||||
self.add_service_item(new_item)
|
self.add_service_item(new_item)
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,8 @@
|
||||||
"""
|
"""
|
||||||
The Themes configuration tab
|
The Themes configuration tab
|
||||||
"""
|
"""
|
||||||
|
from __future__ import division
|
||||||
|
|
||||||
from PyQt4 import QtCore, QtGui
|
from PyQt4 import QtCore, QtGui
|
||||||
|
|
||||||
from openlp.core.lib import Registry, Settings, SettingsTab, UiStrings, translate
|
from openlp.core.lib import Registry, Settings, SettingsTab, UiStrings, translate
|
||||||
|
@ -90,7 +92,7 @@ class ThemesTab(SettingsTab):
|
||||||
self.global_level_label.setObjectName(u'global_level_label')
|
self.global_level_label.setObjectName(u'global_level_label')
|
||||||
self.level_layout.addRow(self.global_level_radio_button, self.global_level_label)
|
self.level_layout.addRow(self.global_level_radio_button, self.global_level_label)
|
||||||
label_top_margin = (self.song_level_radio_button.sizeHint().height() -
|
label_top_margin = (self.song_level_radio_button.sizeHint().height() -
|
||||||
self.song_level_label.sizeHint().height()) / 2
|
self.song_level_label.sizeHint().height()) // 2
|
||||||
for label in [self.song_level_label, self.service_level_label, self.global_level_label]:
|
for label in [self.song_level_label, self.service_level_label, self.global_level_label]:
|
||||||
rect = label.rect()
|
rect = label.rect()
|
||||||
rect.setTop(rect.top() + label_top_margin)
|
rect.setTop(rect.top() + label_top_margin)
|
||||||
|
|
|
@ -58,8 +58,6 @@ class WizardStrings(object):
|
||||||
ImportingType = translate('OpenLP.Ui', 'Importing "%s"...')
|
ImportingType = translate('OpenLP.Ui', 'Importing "%s"...')
|
||||||
ImportSelect = translate('OpenLP.Ui', 'Select Import Source')
|
ImportSelect = translate('OpenLP.Ui', 'Select Import Source')
|
||||||
ImportSelectLong = translate('OpenLP.Ui', 'Select the import format and the location to import from.')
|
ImportSelectLong = translate('OpenLP.Ui', 'Select the import format and the location to import from.')
|
||||||
NoSqlite = translate('OpenLP.Ui', 'The openlp.org 1.x importer has been disabled due to a missing Python module. '
|
|
||||||
'If you want to use this importer, you will need to install the "python-sqlite" module.')
|
|
||||||
OpenTypeFile = translate('OpenLP.Ui', 'Open %s File')
|
OpenTypeFile = translate('OpenLP.Ui', 'Open %s File')
|
||||||
OpenTypeFolder = translate('OpenLP.Ui', 'Open %s Folder')
|
OpenTypeFolder = translate('OpenLP.Ui', 'Open %s Folder')
|
||||||
PercentSymbolFormat = translate('OpenLP.Ui', '%p%')
|
PercentSymbolFormat = translate('OpenLP.Ui', '%p%')
|
||||||
|
|
|
@ -177,9 +177,9 @@ def check_latest_version(current_version):
|
||||||
version_string = current_version[u'full']
|
version_string = current_version[u'full']
|
||||||
# set to prod in the distribution config file.
|
# set to prod in the distribution config file.
|
||||||
settings = Settings()
|
settings = Settings()
|
||||||
settings.beginGroup(u'general')
|
settings.beginGroup(u'core')
|
||||||
last_test = settings.value(u'last version test')
|
last_test = settings.value(u'last version test')
|
||||||
this_test = datetime.now().date()
|
this_test = unicode(datetime.now().date())
|
||||||
settings.setValue(u'last version test', this_test)
|
settings.setValue(u'last version test', this_test)
|
||||||
settings.endGroup()
|
settings.endGroup()
|
||||||
# Tell the main window whether there will ever be data to display
|
# Tell the main window whether there will ever be data to display
|
||||||
|
@ -239,8 +239,7 @@ def get_images_filter():
|
||||||
global IMAGES_FILTER
|
global IMAGES_FILTER
|
||||||
if not IMAGES_FILTER:
|
if not IMAGES_FILTER:
|
||||||
log.debug(u'Generating images filter.')
|
log.debug(u'Generating images filter.')
|
||||||
formats = [unicode(fmt)
|
formats = map(unicode, QtGui.QImageReader.supportedImageFormats())
|
||||||
for fmt in QtGui.QImageReader.supportedImageFormats()]
|
|
||||||
visible_formats = u'(*.%s)' % u'; *.'.join(formats)
|
visible_formats = u'(*.%s)' % u'; *.'.join(formats)
|
||||||
actual_formats = u'(*.%s)' % u' *.'.join(formats)
|
actual_formats = u'(*.%s)' % u' *.'.join(formats)
|
||||||
IMAGES_FILTER = u'%s %s %s' % (translate('OpenLP', 'Image Files'), visible_formats, actual_formats)
|
IMAGES_FILTER = u'%s %s %s' % (translate('OpenLP', 'Image Files'), visible_formats, actual_formats)
|
||||||
|
|
|
@ -98,7 +98,7 @@ class LanguageManager(object):
|
||||||
"""
|
"""
|
||||||
Retrieve a saved language to use from settings
|
Retrieve a saved language to use from settings
|
||||||
"""
|
"""
|
||||||
language = Settings().value(u'general/language')
|
language = Settings().value(u'core/language')
|
||||||
language = str(language)
|
language = str(language)
|
||||||
log.info(u'Language file: \'%s\' Loaded from conf file' % language)
|
log.info(u'Language file: \'%s\' Loaded from conf file' % language)
|
||||||
if re.match(r'[[].*[]]', language):
|
if re.match(r'[[].*[]]', language):
|
||||||
|
@ -128,7 +128,7 @@ class LanguageManager(object):
|
||||||
language = unicode(qm_list[action_name])
|
language = unicode(qm_list[action_name])
|
||||||
if LanguageManager.auto_language:
|
if LanguageManager.auto_language:
|
||||||
language = u'[%s]' % language
|
language = u'[%s]' % language
|
||||||
Settings().setValue(u'general/language', language)
|
Settings().setValue(u'core/language', language)
|
||||||
log.info(u'Language file: \'%s\' written to conf file' % language)
|
log.info(u'Language file: \'%s\' written to conf file' % language)
|
||||||
if message:
|
if message:
|
||||||
QtGui.QMessageBox.information(None,
|
QtGui.QMessageBox.information(None,
|
||||||
|
|
|
@ -27,6 +27,5 @@
|
||||||
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
||||||
###############################################################################
|
###############################################################################
|
||||||
"""
|
"""
|
||||||
The :mod:`alerts` module provides the Alerts plugin for producing impromptu
|
The :mod:`alerts` module provides the Alerts plugin for producing impromptu on-screen announcements during a service.
|
||||||
on-screen announcements during a service.
|
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -115,13 +115,13 @@ HTML = """
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__default_settings__ = {
|
__default_settings__ = {
|
||||||
u'alerts/font face': QtGui.QFont().family(),
|
u'alerts/font face': QtGui.QFont().family(),
|
||||||
u'alerts/font size': 40,
|
u'alerts/font size': 40,
|
||||||
u'alerts/db type': u'sqlite',
|
u'alerts/db type': u'sqlite',
|
||||||
u'alerts/location': AlertLocation.Bottom,
|
u'alerts/location': AlertLocation.Bottom,
|
||||||
u'alerts/background color': u'#660000',
|
u'alerts/background color': u'#660000',
|
||||||
u'alerts/font color': u'#ffffff',
|
u'alerts/font color': u'#ffffff',
|
||||||
u'alerts/timeout': 5
|
u'alerts/timeout': 5
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -139,12 +139,10 @@ class AlertsPlugin(Plugin):
|
||||||
|
|
||||||
def add_tools_menu_item(self, tools_menu):
|
def add_tools_menu_item(self, tools_menu):
|
||||||
"""
|
"""
|
||||||
Give the alerts plugin the opportunity to add items to the
|
Give the alerts plugin the opportunity to add items to the **Tools** menu.
|
||||||
**Tools** menu.
|
|
||||||
|
|
||||||
``tools_menu``
|
``tools_menu``
|
||||||
The actual **Tools** menu item, so that your actions can
|
The actual **Tools** menu item, so that your actions can use it as their parent.
|
||||||
use it as their parent.
|
|
||||||
"""
|
"""
|
||||||
log.info(u'add tools menu')
|
log.info(u'add tools menu')
|
||||||
self.tools_alert_item = create_action(tools_menu, u'toolsAlertItem',
|
self.tools_alert_item = create_action(tools_menu, u'toolsAlertItem',
|
||||||
|
|
|
@ -27,20 +27,16 @@
|
||||||
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
||||||
###############################################################################
|
###############################################################################
|
||||||
"""
|
"""
|
||||||
Forms in OpenLP are made up of two classes. One class holds all the graphical
|
Forms in OpenLP are made up of two classes. One class holds all the graphical elements, like buttons and lists, and the
|
||||||
elements, like buttons and lists, and the other class holds all the functional
|
other class holds all the functional code, like slots and loading and saving.
|
||||||
code, like slots and loading and saving.
|
|
||||||
|
|
||||||
The first class, commonly known as the **Dialog** class, is typically named
|
The first class, commonly known as the **Dialog** class, is typically named ``Ui_<name>Dialog``. It is a slightly
|
||||||
``Ui_<name>Dialog``. It is a slightly modified version of the class that the
|
modified version of the class that the ``pyuic4`` command produces from Qt4's .ui file. Typical modifications will be
|
||||||
``pyuic4`` command produces from Qt4's .ui file. Typical modifications will be
|
converting most strings from "" to u'' and using OpenLP's ``translate()`` function for translating strings.
|
||||||
converting most strings from "" to u'' and using OpenLP's ``translate()``
|
|
||||||
function for translating strings.
|
|
||||||
|
|
||||||
The second class, commonly known as the **Form** class, is typically named
|
The second class, commonly known as the **Form** class, is typically named ``<name>Form``. This class is the one which
|
||||||
``<name>Form``. This class is the one which is instantiated and used. It uses
|
is instantiated and used. It uses dual inheritance to inherit from (usually) QtGui.QDialog and the Ui class mentioned
|
||||||
dual inheritance to inherit from (usually) QtGui.QDialog and the Ui class
|
above, like so::
|
||||||
mentioned above, like so::
|
|
||||||
|
|
||||||
class AuthorsForm(QtGui.QDialog, Ui_AuthorsDialog):
|
class AuthorsForm(QtGui.QDialog, Ui_AuthorsDialog):
|
||||||
|
|
||||||
|
@ -48,9 +44,8 @@ mentioned above, like so::
|
||||||
QtGui.QDialog.__init__(self, parent)
|
QtGui.QDialog.__init__(self, parent)
|
||||||
self.setupUi(self)
|
self.setupUi(self)
|
||||||
|
|
||||||
This allows OpenLP to use ``self.object`` for all the GUI elements while keeping
|
This allows OpenLP to use ``self.object`` for all the GUI elements while keeping them separate from the functionality,
|
||||||
them separate from the functionality, so that it is easier to recreate the GUI
|
so that it is easier to recreate the GUI from the .ui files later if necessary.
|
||||||
from the .ui files later if necessary.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from alertform import AlertForm
|
from alertform import AlertForm
|
||||||
|
|
|
@ -71,13 +71,13 @@ class Ui_AlertDialog(object):
|
||||||
self.save_button.setObjectName(u'save_button')
|
self.save_button.setObjectName(u'save_button')
|
||||||
self.manage_button_layout.addWidget(self.save_button)
|
self.manage_button_layout.addWidget(self.save_button)
|
||||||
self.delete_button = create_button(alert_dialog, u'delete_button', role=u'delete', enabled=False,
|
self.delete_button = create_button(alert_dialog, u'delete_button', role=u'delete', enabled=False,
|
||||||
click=alert_dialog.onDeleteButtonClicked)
|
click=alert_dialog.on_delete_button_clicked)
|
||||||
self.manage_button_layout.addWidget(self.delete_button)
|
self.manage_button_layout.addWidget(self.delete_button)
|
||||||
self.manage_button_layout.addStretch()
|
self.manage_button_layout.addStretch()
|
||||||
self.alert_dialog_layout.addLayout(self.manage_button_layout, 1, 1)
|
self.alert_dialog_layout.addLayout(self.manage_button_layout, 1, 1)
|
||||||
displayIcon = build_icon(u':/general/general_live.png')
|
display_icon = build_icon(u':/general/general_live.png')
|
||||||
self.display_button = create_button(alert_dialog, u'display_button', icon=displayIcon, enabled=False)
|
self.display_button = create_button(alert_dialog, u'display_button', icon=display_icon, enabled=False)
|
||||||
self.display_close_button = create_button(alert_dialog, u'display_close_button', icon=displayIcon,
|
self.display_close_button = create_button(alert_dialog, u'display_close_button', icon=display_icon,
|
||||||
enabled=False)
|
enabled=False)
|
||||||
self.button_box = create_button_box(alert_dialog, u'button_box', [u'close'],
|
self.button_box = create_button_box(alert_dialog, u'button_box', [u'close'],
|
||||||
[self.display_button, self.display_close_button])
|
[self.display_button, self.display_close_button])
|
||||||
|
|
|
@ -93,7 +93,7 @@ class AlertForm(QtGui.QDialog, Ui_AlertDialog):
|
||||||
if self.trigger_alert(self.alert_text_edit.text()):
|
if self.trigger_alert(self.alert_text_edit.text()):
|
||||||
self.close()
|
self.close()
|
||||||
|
|
||||||
def onDeleteButtonClicked(self):
|
def on_delete_button_clicked(self):
|
||||||
"""
|
"""
|
||||||
Deletes the selected item.
|
Deletes the selected item.
|
||||||
"""
|
"""
|
||||||
|
@ -160,8 +160,7 @@ class AlertForm(QtGui.QDialog, Ui_AlertDialog):
|
||||||
|
|
||||||
def on_single_click(self):
|
def on_single_click(self):
|
||||||
"""
|
"""
|
||||||
List item has been single clicked to add it to the edit field so it can
|
List item has been single clicked to add it to the edit field so it can be changed.
|
||||||
be changed.
|
|
||||||
"""
|
"""
|
||||||
item = self.alert_list_widget.selectedIndexes()[0]
|
item = self.alert_list_widget.selectedIndexes()[0]
|
||||||
bitem = self.alert_list_widget.item(item.row())
|
bitem = self.alert_list_widget.item(item.row())
|
||||||
|
@ -186,7 +185,7 @@ class AlertForm(QtGui.QDialog, Ui_AlertDialog):
|
||||||
translate('AlertsPlugin.AlertForm', 'No Parameter Found'),
|
translate('AlertsPlugin.AlertForm', 'No Parameter Found'),
|
||||||
translate('AlertsPlugin.AlertForm', 'You have not entered a parameter to be replaced.\n'
|
translate('AlertsPlugin.AlertForm', 'You have not entered a parameter to be replaced.\n'
|
||||||
'Do you want to continue anyway?'),
|
'Do you want to continue anyway?'),
|
||||||
QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.No | QtGui.QMessageBox.Yes)) == QtGui.QMessageBox.No:
|
QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.No | QtGui.QMessageBox.Yes)) == QtGui.QMessageBox.No:
|
||||||
self.parameter_edit.setFocus()
|
self.parameter_edit.setFocus()
|
||||||
return False
|
return False
|
||||||
# The ParameterEdit field is not empty, but we have not found '<>'
|
# The ParameterEdit field is not empty, but we have not found '<>'
|
||||||
|
@ -195,7 +194,7 @@ class AlertForm(QtGui.QDialog, Ui_AlertDialog):
|
||||||
translate('AlertsPlugin.AlertForm', 'No Placeholder Found'),
|
translate('AlertsPlugin.AlertForm', 'No Placeholder Found'),
|
||||||
translate('AlertsPlugin.AlertForm', 'The alert text does not contain \'<>\'.\n'
|
translate('AlertsPlugin.AlertForm', 'The alert text does not contain \'<>\'.\n'
|
||||||
'Do you want to continue anyway?'),
|
'Do you want to continue anyway?'),
|
||||||
QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.No | QtGui.QMessageBox.Yes)) == QtGui.QMessageBox.No:
|
QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.No | QtGui.QMessageBox.Yes)) == QtGui.QMessageBox.No:
|
||||||
self.parameter_edit.setFocus()
|
self.parameter_edit.setFocus()
|
||||||
return False
|
return False
|
||||||
text = text.replace(u'<>', self.parameter_edit.text())
|
text = text.replace(u'<>', self.parameter_edit.text())
|
||||||
|
@ -204,8 +203,8 @@ class AlertForm(QtGui.QDialog, Ui_AlertDialog):
|
||||||
|
|
||||||
def on_current_row_changed(self, row):
|
def on_current_row_changed(self, row):
|
||||||
"""
|
"""
|
||||||
Called when the *alert_list_widget*'s current row has been changed. This
|
Called when the *alert_list_widget*'s current row has been changed. This enables or disables buttons which
|
||||||
enables or disables buttons which require an item to act on.
|
require an item to act on.
|
||||||
|
|
||||||
``row``
|
``row``
|
||||||
The row (int). If there is no current row, the value is -1.
|
The row (int). If there is no current row, the value is -1.
|
||||||
|
|
|
@ -27,8 +27,8 @@
|
||||||
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
||||||
###############################################################################
|
###############################################################################
|
||||||
"""
|
"""
|
||||||
The :mod:`~openlp.plugins.alerts.lib.alertsmanager` module contains the part of
|
The :mod:`~openlp.plugins.alerts.lib.alertsmanager` module contains the part of the plugin which manages storing and
|
||||||
the plugin which manages storing and displaying of alerts.
|
displaying of alerts.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
@ -49,22 +49,23 @@ class AlertsManager(QtCore.QObject):
|
||||||
|
|
||||||
def __init__(self, parent):
|
def __init__(self, parent):
|
||||||
QtCore.QObject.__init__(self, parent)
|
QtCore.QObject.__init__(self, parent)
|
||||||
|
Registry().register(u'alerts_manager', self)
|
||||||
self.timer_id = 0
|
self.timer_id = 0
|
||||||
self.alert_list = []
|
self.alert_list = []
|
||||||
Registry().register_function(u'live_display_active', self.generate_alert)
|
Registry().register_function(u'live_display_active', self.generate_alert)
|
||||||
Registry().register_function(u'alerts_text', self.alert_text)
|
Registry().register_function(u'alerts_text', self.alert_text)
|
||||||
|
QtCore.QObject.connect(self, QtCore.SIGNAL(u'alerts_text'), self.alert_text)
|
||||||
|
|
||||||
def alert_text(self, message):
|
def alert_text(self, message):
|
||||||
"""
|
"""
|
||||||
Called via a alerts_text event. Message is single element array
|
Called via a alerts_text event. Message is single element array containing text.
|
||||||
containing text
|
|
||||||
"""
|
"""
|
||||||
if message:
|
if message:
|
||||||
self.display_alert(message[0])
|
self.display_alert(message[0])
|
||||||
|
|
||||||
def display_alert(self, text=u''):
|
def display_alert(self, text=u''):
|
||||||
"""
|
"""
|
||||||
Called from the Alert Tab to display an alert
|
Called from the Alert Tab to display an alert.
|
||||||
|
|
||||||
``text``
|
``text``
|
||||||
display text
|
display text
|
||||||
|
@ -81,7 +82,7 @@ class AlertsManager(QtCore.QObject):
|
||||||
|
|
||||||
def generate_alert(self):
|
def generate_alert(self):
|
||||||
"""
|
"""
|
||||||
Format and request the Alert and start the timer
|
Format and request the Alert and start the timer.
|
||||||
"""
|
"""
|
||||||
log.debug(u'Generate Alert called')
|
log.debug(u'Generate Alert called')
|
||||||
if not self.alert_list:
|
if not self.alert_list:
|
||||||
|
@ -95,8 +96,7 @@ class AlertsManager(QtCore.QObject):
|
||||||
|
|
||||||
def timerEvent(self, event):
|
def timerEvent(self, event):
|
||||||
"""
|
"""
|
||||||
Time has finished so if our time then request the next Alert
|
Time has finished so if our time then request the next Alert if there is one and reset the timer.
|
||||||
if there is one and reset the timer.
|
|
||||||
|
|
||||||
``event``
|
``event``
|
||||||
the QT event that has been triggered.
|
the QT event that has been triggered.
|
||||||
|
|
|
@ -27,8 +27,7 @@
|
||||||
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
||||||
###############################################################################
|
###############################################################################
|
||||||
"""
|
"""
|
||||||
The :mod:`db` module provides the database and schema that is the backend for
|
The :mod:`db` module provides the database and schema that is the backend for the Alerts plugin.
|
||||||
the Alerts plugin
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from sqlalchemy import Column, Table, types
|
from sqlalchemy import Column, Table, types
|
||||||
|
@ -36,12 +35,14 @@ from sqlalchemy.orm import mapper
|
||||||
|
|
||||||
from openlp.core.lib.db import BaseModel, init_db
|
from openlp.core.lib.db import BaseModel, init_db
|
||||||
|
|
||||||
|
|
||||||
class AlertItem(BaseModel):
|
class AlertItem(BaseModel):
|
||||||
"""
|
"""
|
||||||
AlertItem model
|
AlertItem model
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def init_schema(url):
|
def init_schema(url):
|
||||||
"""
|
"""
|
||||||
Setup the alerts database connection and initialise the database schema
|
Setup the alerts database connection and initialise the database schema
|
||||||
|
|
|
@ -27,6 +27,5 @@
|
||||||
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
||||||
###############################################################################
|
###############################################################################
|
||||||
"""
|
"""
|
||||||
The :mod:`bibles` module provides the Bible plugin to enable OpenLP to display
|
The :mod:`bibles` module provides the Bible plugin to enable OpenLP to display scripture.
|
||||||
scripture.
|
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -43,25 +43,25 @@ log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
__default_settings__ = {
|
__default_settings__ = {
|
||||||
u'bibles/db type': u'sqlite',
|
u'bibles/db type': u'sqlite',
|
||||||
u'bibles/last search type': BibleSearch.Reference,
|
u'bibles/last search type': BibleSearch.Reference,
|
||||||
u'bibles/verse layout style': LayoutStyle.VersePerSlide,
|
u'bibles/verse layout style': LayoutStyle.VersePerSlide,
|
||||||
u'bibles/book name language': LanguageSelection.Bible,
|
u'bibles/book name language': LanguageSelection.Bible,
|
||||||
u'bibles/display brackets': DisplayStyle.NoBrackets,
|
u'bibles/display brackets': DisplayStyle.NoBrackets,
|
||||||
u'bibles/display new chapter': False,
|
u'bibles/display new chapter': False,
|
||||||
u'bibles/second bibles': True,
|
u'bibles/second bibles': True,
|
||||||
u'bibles/advanced bible': u'',
|
u'bibles/advanced bible': u'',
|
||||||
u'bibles/quick bible': u'',
|
u'bibles/quick bible': u'',
|
||||||
u'bibles/proxy name': u'',
|
u'bibles/proxy name': u'',
|
||||||
u'bibles/proxy address': u'',
|
u'bibles/proxy address': u'',
|
||||||
u'bibles/proxy username': u'',
|
u'bibles/proxy username': u'',
|
||||||
u'bibles/proxy password': u'',
|
u'bibles/proxy password': u'',
|
||||||
u'bibles/bible theme': u'',
|
u'bibles/bible theme': u'',
|
||||||
u'bibles/verse separator': u'',
|
u'bibles/verse separator': u'',
|
||||||
u'bibles/range separator': u'',
|
u'bibles/range separator': u'',
|
||||||
u'bibles/list separator': u'',
|
u'bibles/list separator': u'',
|
||||||
u'bibles/end separator': u'',
|
u'bibles/end separator': u'',
|
||||||
u'bibles/last directory import': u''
|
u'bibles/last directory import': u''
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -124,18 +124,15 @@ class BiblePlugin(Plugin):
|
||||||
|
|
||||||
def add_export_menu_Item(self, export_menu):
|
def add_export_menu_Item(self, export_menu):
|
||||||
self.export_bible_item = create_action(export_menu, u'exportBibleItem',
|
self.export_bible_item = create_action(export_menu, u'exportBibleItem',
|
||||||
text=translate('BiblesPlugin', '&Bible'),
|
text=translate('BiblesPlugin', '&Bible'), visible=False)
|
||||||
visible=False)
|
|
||||||
export_menu.addAction(self.export_bible_item)
|
export_menu.addAction(self.export_bible_item)
|
||||||
|
|
||||||
def add_tools_menu_item(self, tools_menu):
|
def add_tools_menu_item(self, tools_menu):
|
||||||
"""
|
"""
|
||||||
Give the bible plugin the opportunity to add items to the
|
Give the bible plugin the opportunity to add items to the **Tools** menu.
|
||||||
**Tools** menu.
|
|
||||||
|
|
||||||
``tools_menu``
|
``tools_menu``
|
||||||
The actual **Tools** menu item, so that your actions can
|
The actual **Tools** menu item, so that your actions can use it as their parent.
|
||||||
use it as their parent.
|
|
||||||
"""
|
"""
|
||||||
log.debug(u'add tools menu')
|
log.debug(u'add tools menu')
|
||||||
self.tools_upgrade_item = create_action(tools_menu, u'toolsUpgradeItem',
|
self.tools_upgrade_item = create_action(tools_menu, u'toolsUpgradeItem',
|
||||||
|
@ -166,25 +163,23 @@ class BiblePlugin(Plugin):
|
||||||
|
|
||||||
def uses_theme(self, theme):
|
def uses_theme(self, theme):
|
||||||
"""
|
"""
|
||||||
Called to find out if the bible plugin is currently using a theme.
|
Called to find out if the bible plugin is currently using a theme. Returns ``True`` if the theme is being used,
|
||||||
Returns ``True`` if the theme is being used, otherwise returns
|
otherwise returns ``False``.
|
||||||
``False``.
|
|
||||||
"""
|
"""
|
||||||
return unicode(self.settings_tab.bible_theme) == theme
|
return unicode(self.settings_tab.bible_theme) == theme
|
||||||
|
|
||||||
def rename_theme(self, oldTheme, newTheme):
|
def rename_theme(self, old_theme, new_theme):
|
||||||
"""
|
"""
|
||||||
Rename the theme the bible plugin is using making the plugin use the
|
Rename the theme the bible plugin is using making the plugin use the
|
||||||
new name.
|
new name.
|
||||||
|
|
||||||
``oldTheme``
|
``old_theme``
|
||||||
The name of the theme the plugin should stop using. Unused for
|
The name of the theme the plugin should stop using. Unused for this particular plugin.
|
||||||
this particular plugin.
|
|
||||||
|
|
||||||
``newTheme``
|
``new_theme``
|
||||||
The new name the plugin should now use.
|
The new name the plugin should now use.
|
||||||
"""
|
"""
|
||||||
self.settings_tab.bible_theme = newTheme
|
self.settings_tab.bible_theme = new_theme
|
||||||
self.settings_tab.save()
|
self.settings_tab.save()
|
||||||
|
|
||||||
def set_plugin_text_strings(self):
|
def set_plugin_text_strings(self):
|
||||||
|
|
|
@ -28,30 +28,25 @@
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Forms in OpenLP are made up of two classes. One class holds all the graphical
|
Forms in OpenLP are made up of two classes. One class holds all the graphical elements, like buttons and lists, and the
|
||||||
elements, like buttons and lists, and the other class holds all the functional
|
other class holds all the functional code, like slots and loading and saving.
|
||||||
code, like slots and loading and saving.
|
|
||||||
|
|
||||||
The first class, commonly known as the **Dialog** class, is typically named
|
The first class, commonly known as the **Dialog** class, is typically named ``Ui_<name>Dialog``. It is a slightly
|
||||||
``Ui_<name>Dialog``. It is a slightly modified version of the class that the
|
modified version of the class that the ``pyuic4`` command produces from Qt4's .ui file. Typical modifications will be
|
||||||
``pyuic4`` command produces from Qt4's .ui file. Typical modifications will be
|
converting most strings from "" to u'' and using OpenLP's ``translate()`` function for translating strings.
|
||||||
converting most strings from "" to u'' and using OpenLP's ``translate()``
|
|
||||||
function for translating strings.
|
|
||||||
|
|
||||||
The second class, commonly known as the **Form** class, is typically named
|
The second class, commonly known as the **Form** class, is typically named ``<name>Form``. This class is the one which
|
||||||
``<name>Form``. This class is the one which is instantiated and used. It uses
|
is instantiated and used. It uses dual inheritance to inherit from (usually) QtGui.QDialog and the Ui class mentioned
|
||||||
dual inheritance to inherit from (usually) QtGui.QDialog and the Ui class
|
above, like so::
|
||||||
mentioned above, like so::
|
|
||||||
|
|
||||||
class BibleImportForm(QtGui.QWizard, Ui_BibleImportWizard):
|
class BibleImportForm(QtGui.QWizard, Ui_BibleImportWizard):
|
||||||
|
|
||||||
def __init__(self, parent, manager, bibleplugin):
|
def __init__(self, parent, manager, bible_plugin):
|
||||||
QtGui.QWizard.__init__(self, parent)
|
QtGui.QWizard.__init__(self, parent)
|
||||||
self.setupUi(self)
|
self.setupUi(self)
|
||||||
|
|
||||||
This allows OpenLP to use ``self.object`` for all the GUI elements while keeping
|
This allows OpenLP to use ``self.object`` for all the GUI elements while keeping them separate from the functionality,
|
||||||
them separate from the functionality, so that it is easier to recreate the GUI
|
so that it is easier to recreate the GUI from the .ui files later if necessary.
|
||||||
from the .ui files later if necessary.
|
|
||||||
"""
|
"""
|
||||||
from booknameform import BookNameForm
|
from booknameform import BookNameForm
|
||||||
from languageform import LanguageForm
|
from languageform import LanguageForm
|
||||||
|
@ -59,5 +54,4 @@ from bibleimportform import BibleImportForm
|
||||||
from bibleupgradeform import BibleUpgradeForm
|
from bibleupgradeform import BibleUpgradeForm
|
||||||
from editbibleform import EditBibleForm
|
from editbibleform import EditBibleForm
|
||||||
|
|
||||||
__all__ = [u'BookNameForm', u'LanguageForm', u'BibleImportForm',
|
__all__ = [u'BookNameForm', u'LanguageForm', u'BibleImportForm', u'BibleUpgradeForm', u'EditBibleForm']
|
||||||
u'BibleUpgradeForm', u'EditBibleForm']
|
|
||||||
|
|
|
@ -58,12 +58,12 @@ class WebDownload(object):
|
||||||
|
|
||||||
class BibleImportForm(OpenLPWizard):
|
class BibleImportForm(OpenLPWizard):
|
||||||
"""
|
"""
|
||||||
This is the Bible Import Wizard, which allows easy importing of Bibles
|
This is the Bible Import Wizard, which allows easy importing of Bibles into OpenLP from other formats like OSIS,
|
||||||
into OpenLP from other formats like OSIS, CSV and OpenSong.
|
CSV and OpenSong.
|
||||||
"""
|
"""
|
||||||
log.info(u'BibleImportForm loaded')
|
log.info(u'BibleImportForm loaded')
|
||||||
|
|
||||||
def __init__(self, parent, manager, bibleplugin):
|
def __init__(self, parent, manager, bible_plugin):
|
||||||
"""
|
"""
|
||||||
Instantiate the wizard, and run any extra setup we need to.
|
Instantiate the wizard, and run any extra setup we need to.
|
||||||
|
|
||||||
|
@ -73,12 +73,12 @@ class BibleImportForm(OpenLPWizard):
|
||||||
``manager``
|
``manager``
|
||||||
The Bible manager.
|
The Bible manager.
|
||||||
|
|
||||||
``bibleplugin``
|
``bible_plugin``
|
||||||
The Bible plugin.
|
The Bible plugin.
|
||||||
"""
|
"""
|
||||||
self.manager = manager
|
self.manager = manager
|
||||||
self.web_bible_list = {}
|
self.web_bible_list = {}
|
||||||
OpenLPWizard.__init__(self, parent, bibleplugin, u'bibleImportWizard', u':/wizards/wizard_importbible.bmp')
|
OpenLPWizard.__init__(self, parent, bible_plugin, u'bibleImportWizard', u':/wizards/wizard_importbible.bmp')
|
||||||
|
|
||||||
def setupUi(self, image):
|
def setupUi(self, image):
|
||||||
"""
|
"""
|
||||||
|
@ -94,19 +94,11 @@ class BibleImportForm(OpenLPWizard):
|
||||||
button.
|
button.
|
||||||
"""
|
"""
|
||||||
self.selectStack.setCurrentIndex(index)
|
self.selectStack.setCurrentIndex(index)
|
||||||
next_button = self.button(QtGui.QWizard.NextButton)
|
|
||||||
next_button.setEnabled(BibleFormat.get_availability(index))
|
|
||||||
|
|
||||||
def custom_init(self):
|
def custom_init(self):
|
||||||
"""
|
"""
|
||||||
Perform any custom initialisation for bible importing.
|
Perform any custom initialisation for bible importing.
|
||||||
"""
|
"""
|
||||||
if BibleFormat.get_availability(BibleFormat.OpenLP1):
|
|
||||||
self.openlp1DisabledLabel.hide()
|
|
||||||
else:
|
|
||||||
self.openlp1FileLabel.hide()
|
|
||||||
self.openlp1FileEdit.hide()
|
|
||||||
self.openlp1BrowseButton.hide()
|
|
||||||
self.manager.set_process_dialog(self)
|
self.manager.set_process_dialog(self)
|
||||||
self.loadWebBibles()
|
self.loadWebBibles()
|
||||||
self.restart()
|
self.restart()
|
||||||
|
@ -121,7 +113,6 @@ class BibleImportForm(OpenLPWizard):
|
||||||
self.csvBooksButton.clicked.connect(self.onCsvBooksBrowseButtonClicked)
|
self.csvBooksButton.clicked.connect(self.onCsvBooksBrowseButtonClicked)
|
||||||
self.csvVersesButton.clicked.connect(self.onCsvVersesBrowseButtonClicked)
|
self.csvVersesButton.clicked.connect(self.onCsvVersesBrowseButtonClicked)
|
||||||
self.openSongBrowseButton.clicked.connect(self.onOpenSongBrowseButtonClicked)
|
self.openSongBrowseButton.clicked.connect(self.onOpenSongBrowseButtonClicked)
|
||||||
self.openlp1BrowseButton.clicked.connect(self.onOpenlp1BrowseButtonClicked)
|
|
||||||
|
|
||||||
def add_custom_pages(self):
|
def add_custom_pages(self):
|
||||||
"""
|
"""
|
||||||
|
@ -137,7 +128,7 @@ class BibleImportForm(OpenLPWizard):
|
||||||
self.formatLabel = QtGui.QLabel(self.selectPage)
|
self.formatLabel = QtGui.QLabel(self.selectPage)
|
||||||
self.formatLabel.setObjectName(u'FormatLabel')
|
self.formatLabel.setObjectName(u'FormatLabel')
|
||||||
self.formatComboBox = QtGui.QComboBox(self.selectPage)
|
self.formatComboBox = QtGui.QComboBox(self.selectPage)
|
||||||
self.formatComboBox.addItems([u'', u'', u'', u'', u''])
|
self.formatComboBox.addItems([u'', u'', u'', u''])
|
||||||
self.formatComboBox.setObjectName(u'FormatComboBox')
|
self.formatComboBox.setObjectName(u'FormatComboBox')
|
||||||
self.formatLayout.addRow(self.formatLabel, self.formatComboBox)
|
self.formatLayout.addRow(self.formatLabel, self.formatComboBox)
|
||||||
self.spacer = QtGui.QSpacerItem(10, 0, QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Minimum)
|
self.spacer = QtGui.QSpacerItem(10, 0, QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Minimum)
|
||||||
|
@ -259,29 +250,6 @@ class BibleImportForm(OpenLPWizard):
|
||||||
self.webProxyLayout.setWidget(2, QtGui.QFormLayout.FieldRole, self.webPasswordEdit)
|
self.webProxyLayout.setWidget(2, QtGui.QFormLayout.FieldRole, self.webPasswordEdit)
|
||||||
self.webTabWidget.addTab(self.webProxyTab, u'')
|
self.webTabWidget.addTab(self.webProxyTab, u'')
|
||||||
self.selectStack.addWidget(self.webTabWidget)
|
self.selectStack.addWidget(self.webTabWidget)
|
||||||
self.openlp1Widget = QtGui.QWidget(self.selectPage)
|
|
||||||
self.openlp1Widget.setObjectName(u'Openlp1Widget')
|
|
||||||
self.openlp1Layout = QtGui.QFormLayout(self.openlp1Widget)
|
|
||||||
self.openlp1Layout.setMargin(0)
|
|
||||||
self.openlp1Layout.setObjectName(u'Openlp1Layout')
|
|
||||||
self.openlp1FileLabel = QtGui.QLabel(self.openlp1Widget)
|
|
||||||
self.openlp1FileLabel.setObjectName(u'Openlp1FileLabel')
|
|
||||||
self.openlp1FileLayout = QtGui.QHBoxLayout()
|
|
||||||
self.openlp1FileLayout.setObjectName(u'Openlp1FileLayout')
|
|
||||||
self.openlp1FileEdit = QtGui.QLineEdit(self.openlp1Widget)
|
|
||||||
self.openlp1FileEdit.setObjectName(u'Openlp1FileEdit')
|
|
||||||
self.openlp1FileLayout.addWidget(self.openlp1FileEdit)
|
|
||||||
self.openlp1BrowseButton = QtGui.QToolButton(self.openlp1Widget)
|
|
||||||
self.openlp1BrowseButton.setIcon(self.open_icon)
|
|
||||||
self.openlp1BrowseButton.setObjectName(u'Openlp1BrowseButton')
|
|
||||||
self.openlp1FileLayout.addWidget(self.openlp1BrowseButton)
|
|
||||||
self.openlp1Layout.addRow(self.openlp1FileLabel, self.openlp1FileLayout)
|
|
||||||
self.openlp1DisabledLabel = QtGui.QLabel(self.openlp1Widget)
|
|
||||||
self.openlp1DisabledLabel.setWordWrap(True)
|
|
||||||
self.openlp1DisabledLabel.setObjectName(u'Openlp1DisabledLabel')
|
|
||||||
self.openlp1Layout.addRow(self.openlp1DisabledLabel)
|
|
||||||
self.openlp1Layout.setItem(1, QtGui.QFormLayout.LabelRole, self.spacer)
|
|
||||||
self.selectStack.addWidget(self.openlp1Widget)
|
|
||||||
self.selectPageLayout.addLayout(self.selectStack)
|
self.selectPageLayout.addLayout(self.selectStack)
|
||||||
self.addPage(self.selectPage)
|
self.addPage(self.selectPage)
|
||||||
# License Page
|
# License Page
|
||||||
|
@ -330,8 +298,6 @@ class BibleImportForm(OpenLPWizard):
|
||||||
self.formatComboBox.setItemText(BibleFormat.OpenSong, WizardStrings.OS)
|
self.formatComboBox.setItemText(BibleFormat.OpenSong, WizardStrings.OS)
|
||||||
self.formatComboBox.setItemText(BibleFormat.WebDownload,
|
self.formatComboBox.setItemText(BibleFormat.WebDownload,
|
||||||
translate('BiblesPlugin.ImportWizardForm', 'Web Download'))
|
translate('BiblesPlugin.ImportWizardForm', 'Web Download'))
|
||||||
self.formatComboBox.setItemText(BibleFormat.OpenLP1, UiStrings().OLPV1)
|
|
||||||
self.openlp1FileLabel.setText(translate('BiblesPlugin.ImportWizardForm', 'Bible file:'))
|
|
||||||
self.osisFileLabel.setText(translate('BiblesPlugin.ImportWizardForm', 'Bible file:'))
|
self.osisFileLabel.setText(translate('BiblesPlugin.ImportWizardForm', 'Bible file:'))
|
||||||
self.csvBooksLabel.setText(translate('BiblesPlugin.ImportWizardForm', 'Books file:'))
|
self.csvBooksLabel.setText(translate('BiblesPlugin.ImportWizardForm', 'Books file:'))
|
||||||
self.csvVersesLabel.setText(translate('BiblesPlugin.ImportWizardForm', 'Verses file:'))
|
self.csvVersesLabel.setText(translate('BiblesPlugin.ImportWizardForm', 'Verses file:'))
|
||||||
|
@ -364,14 +330,12 @@ class BibleImportForm(OpenLPWizard):
|
||||||
'Please wait while your Bible is imported.'))
|
'Please wait while your Bible is imported.'))
|
||||||
self.progress_label.setText(WizardStrings.Ready)
|
self.progress_label.setText(WizardStrings.Ready)
|
||||||
self.progress_bar.setFormat(u'%p%')
|
self.progress_bar.setFormat(u'%p%')
|
||||||
self.openlp1DisabledLabel.setText(WizardStrings.NoSqlite)
|
|
||||||
# Align all QFormLayouts towards each other.
|
# Align all QFormLayouts towards each other.
|
||||||
labelWidth = max(self.formatLabel.minimumSizeHint().width(),
|
labelWidth = max(self.formatLabel.minimumSizeHint().width(),
|
||||||
self.osisFileLabel.minimumSizeHint().width(),
|
self.osisFileLabel.minimumSizeHint().width(),
|
||||||
self.csvBooksLabel.minimumSizeHint().width(),
|
self.csvBooksLabel.minimumSizeHint().width(),
|
||||||
self.csvVersesLabel.minimumSizeHint().width(),
|
self.csvVersesLabel.minimumSizeHint().width(),
|
||||||
self.openSongFileLabel.minimumSizeHint().width(),
|
self.openSongFileLabel.minimumSizeHint().width())
|
||||||
self.openlp1FileLabel.minimumSizeHint().width())
|
|
||||||
self.spacer.changeSize(labelWidth, 0, QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed)
|
self.spacer.changeSize(labelWidth, 0, QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed)
|
||||||
|
|
||||||
def validateCurrentPage(self):
|
def validateCurrentPage(self):
|
||||||
|
@ -406,11 +370,6 @@ class BibleImportForm(OpenLPWizard):
|
||||||
elif self.field(u'source_format') == BibleFormat.WebDownload:
|
elif self.field(u'source_format') == BibleFormat.WebDownload:
|
||||||
self.versionNameEdit.setText(self.webTranslationComboBox.currentText())
|
self.versionNameEdit.setText(self.webTranslationComboBox.currentText())
|
||||||
return True
|
return True
|
||||||
elif self.field(u'source_format') == BibleFormat.OpenLP1:
|
|
||||||
if not self.field(u'openlp1_location'):
|
|
||||||
critical_error_message_box(UiStrings().NFSs, WizardStrings.YouSpecifyFile % UiStrings().OLPV1)
|
|
||||||
self.openlp1FileEdit.setFocus()
|
|
||||||
return False
|
|
||||||
return True
|
return True
|
||||||
elif self.currentPage() == self.licenseDetailsPage:
|
elif self.currentPage() == self.licenseDetailsPage:
|
||||||
license_version = self.field(u'license_version')
|
license_version = self.field(u'license_version')
|
||||||
|
@ -484,13 +443,6 @@ class BibleImportForm(OpenLPWizard):
|
||||||
"""
|
"""
|
||||||
self.get_file_name(WizardStrings.OpenTypeFile % WizardStrings.OS, self.openSongFileEdit, u'last directory import')
|
self.get_file_name(WizardStrings.OpenTypeFile % WizardStrings.OS, self.openSongFileEdit, u'last directory import')
|
||||||
|
|
||||||
def onOpenlp1BrowseButtonClicked(self):
|
|
||||||
"""
|
|
||||||
Show the file open dialog for the openlp.org 1.x file.
|
|
||||||
"""
|
|
||||||
self.get_file_name(WizardStrings.OpenTypeFile % UiStrings().OLPV1, self.openlp1FileEdit, u'last directory import',
|
|
||||||
u'%s (*.bible)' % translate('BiblesPlugin.ImportWizardForm', 'openlp.org 1.x Bible Files'))
|
|
||||||
|
|
||||||
def register_fields(self):
|
def register_fields(self):
|
||||||
"""
|
"""
|
||||||
Register the bible import wizard fields.
|
Register the bible import wizard fields.
|
||||||
|
@ -505,7 +457,6 @@ class BibleImportForm(OpenLPWizard):
|
||||||
self.selectPage.registerField(u'proxy_server', self.webServerEdit)
|
self.selectPage.registerField(u'proxy_server', self.webServerEdit)
|
||||||
self.selectPage.registerField(u'proxy_username', self.webUserEdit)
|
self.selectPage.registerField(u'proxy_username', self.webUserEdit)
|
||||||
self.selectPage.registerField(u'proxy_password', self.webPasswordEdit)
|
self.selectPage.registerField(u'proxy_password', self.webPasswordEdit)
|
||||||
self.selectPage.registerField(u'openlp1_location', self.openlp1FileEdit)
|
|
||||||
self.licenseDetailsPage.registerField(u'license_version', self.versionNameEdit)
|
self.licenseDetailsPage.registerField(u'license_version', self.versionNameEdit)
|
||||||
self.licenseDetailsPage.registerField(u'license_copyright', self.copyrightEdit)
|
self.licenseDetailsPage.registerField(u'license_copyright', self.copyrightEdit)
|
||||||
self.licenseDetailsPage.registerField(u'license_permissions', self.permissionsEdit)
|
self.licenseDetailsPage.registerField(u'license_permissions', self.permissionsEdit)
|
||||||
|
@ -529,7 +480,6 @@ class BibleImportForm(OpenLPWizard):
|
||||||
self.setField(u'proxy_server', settings.value(u'proxy address'))
|
self.setField(u'proxy_server', settings.value(u'proxy address'))
|
||||||
self.setField(u'proxy_username', settings.value(u'proxy username'))
|
self.setField(u'proxy_username', settings.value(u'proxy username'))
|
||||||
self.setField(u'proxy_password', settings.value(u'proxy password'))
|
self.setField(u'proxy_password', settings.value(u'proxy password'))
|
||||||
self.setField(u'openlp1_location', '')
|
|
||||||
self.setField(u'license_version', self.versionNameEdit.text())
|
self.setField(u'license_version', self.versionNameEdit.text())
|
||||||
self.setField(u'license_copyright', self.copyrightEdit.text())
|
self.setField(u'license_copyright', self.copyrightEdit.text())
|
||||||
self.setField(u'license_permissions', self.permissionsEdit.text())
|
self.setField(u'license_permissions', self.permissionsEdit.text())
|
||||||
|
@ -561,7 +511,7 @@ class BibleImportForm(OpenLPWizard):
|
||||||
name = bible[u'abbreviation']
|
name = bible[u'abbreviation']
|
||||||
self.web_bible_list[download_type][version] = name.strip()
|
self.web_bible_list[download_type][version] = name.strip()
|
||||||
|
|
||||||
def preWizard(self):
|
def pre_wizard(self):
|
||||||
"""
|
"""
|
||||||
Prepare the UI for the import.
|
Prepare the UI for the import.
|
||||||
"""
|
"""
|
||||||
|
@ -615,12 +565,6 @@ class BibleImportForm(OpenLPWizard):
|
||||||
proxy_username=self.field(u'proxy_username'),
|
proxy_username=self.field(u'proxy_username'),
|
||||||
proxy_password=self.field(u'proxy_password')
|
proxy_password=self.field(u'proxy_password')
|
||||||
)
|
)
|
||||||
elif bible_type == BibleFormat.OpenLP1:
|
|
||||||
# Import an openlp.org 1.x bible.
|
|
||||||
importer = self.manager.import_bible(BibleFormat.OpenLP1,
|
|
||||||
name=license_version,
|
|
||||||
filename=self.field(u'openlp1_location')
|
|
||||||
)
|
|
||||||
if importer.do_import(license_version):
|
if importer.do_import(license_version):
|
||||||
self.manager.save_meta_data(license_version, license_version,
|
self.manager.save_meta_data(license_version, license_version,
|
||||||
license_copyright, license_permissions)
|
license_copyright, license_permissions)
|
||||||
|
|
|
@ -48,8 +48,8 @@ log = logging.getLogger(__name__)
|
||||||
|
|
||||||
class BibleUpgradeForm(OpenLPWizard):
|
class BibleUpgradeForm(OpenLPWizard):
|
||||||
"""
|
"""
|
||||||
This is the Bible Upgrade Wizard, which allows easy importing of Bibles
|
This is the Bible Upgrade Wizard, which allows easy importing of Bibles into OpenLP from older OpenLP2 database
|
||||||
into OpenLP from older OpenLP2 database versions.
|
versions.
|
||||||
"""
|
"""
|
||||||
log.info(u'BibleUpgradeForm loaded')
|
log.info(u'BibleUpgradeForm loaded')
|
||||||
|
|
||||||
|
@ -63,7 +63,7 @@ class BibleUpgradeForm(OpenLPWizard):
|
||||||
``manager``
|
``manager``
|
||||||
The Bible manager.
|
The Bible manager.
|
||||||
|
|
||||||
``bibleplugin``
|
``bible_plugin``
|
||||||
The Bible plugin.
|
The Bible plugin.
|
||||||
"""
|
"""
|
||||||
self.manager = manager
|
self.manager = manager
|
||||||
|
@ -74,7 +74,7 @@ class BibleUpgradeForm(OpenLPWizard):
|
||||||
self.temp_dir = os.path.join(unicode(gettempdir(), get_filesystem_encoding()), u'openlp')
|
self.temp_dir = os.path.join(unicode(gettempdir(), get_filesystem_encoding()), u'openlp')
|
||||||
self.files = self.manager.old_bible_databases
|
self.files = self.manager.old_bible_databases
|
||||||
self.success = {}
|
self.success = {}
|
||||||
self.newbibles = {}
|
self.new_bibles = {}
|
||||||
OpenLPWizard.__init__(self, parent, bible_plugin, u'bibleUpgradeWizard', u':/wizards/wizard_importbible.bmp')
|
OpenLPWizard.__init__(self, parent, bible_plugin, u'bibleUpgradeWizard', u':/wizards/wizard_importbible.bmp')
|
||||||
|
|
||||||
def setupUi(self, image):
|
def setupUi(self, image):
|
||||||
|
@ -105,7 +105,7 @@ class BibleUpgradeForm(OpenLPWizard):
|
||||||
Perform necessary functions depending on which wizard page is active.
|
Perform necessary functions depending on which wizard page is active.
|
||||||
"""
|
"""
|
||||||
if self.page(pageId) == self.progress_page:
|
if self.page(pageId) == self.progress_page:
|
||||||
self.preWizard()
|
self.pre_wizard()
|
||||||
self.performWizard()
|
self.performWizard()
|
||||||
self.post_wizard()
|
self.post_wizard()
|
||||||
elif self.page(pageId) == self.selectPage and not self.files:
|
elif self.page(pageId) == self.selectPage and not self.files:
|
||||||
|
@ -159,41 +159,41 @@ class BibleUpgradeForm(OpenLPWizard):
|
||||||
Add the bible import specific wizard pages.
|
Add the bible import specific wizard pages.
|
||||||
"""
|
"""
|
||||||
# Backup Page
|
# Backup Page
|
||||||
self.backupPage = QtGui.QWizardPage()
|
self.backup_page = QtGui.QWizardPage()
|
||||||
self.backupPage.setObjectName(u'BackupPage')
|
self.backup_page.setObjectName(u'BackupPage')
|
||||||
self.backupLayout = QtGui.QVBoxLayout(self.backupPage)
|
self.backupLayout = QtGui.QVBoxLayout(self.backup_page)
|
||||||
self.backupLayout.setObjectName(u'BackupLayout')
|
self.backupLayout.setObjectName(u'BackupLayout')
|
||||||
self.backupInfoLabel = QtGui.QLabel(self.backupPage)
|
self.backupInfoLabel = QtGui.QLabel(self.backup_page)
|
||||||
self.backupInfoLabel.setOpenExternalLinks(True)
|
self.backupInfoLabel.setOpenExternalLinks(True)
|
||||||
self.backupInfoLabel.setTextFormat(QtCore.Qt.RichText)
|
self.backupInfoLabel.setTextFormat(QtCore.Qt.RichText)
|
||||||
self.backupInfoLabel.setWordWrap(True)
|
self.backupInfoLabel.setWordWrap(True)
|
||||||
self.backupInfoLabel.setObjectName(u'backupInfoLabel')
|
self.backupInfoLabel.setObjectName(u'backupInfoLabel')
|
||||||
self.backupLayout.addWidget(self.backupInfoLabel)
|
self.backupLayout.addWidget(self.backupInfoLabel)
|
||||||
self.selectLabel = QtGui.QLabel(self.backupPage)
|
self.selectLabel = QtGui.QLabel(self.backup_page)
|
||||||
self.selectLabel.setObjectName(u'select_label')
|
self.selectLabel.setObjectName(u'select_label')
|
||||||
self.backupLayout.addWidget(self.selectLabel)
|
self.backupLayout.addWidget(self.selectLabel)
|
||||||
self.formLayout = QtGui.QFormLayout()
|
self.formLayout = QtGui.QFormLayout()
|
||||||
self.formLayout.setMargin(0)
|
self.formLayout.setMargin(0)
|
||||||
self.formLayout.setObjectName(u'FormLayout')
|
self.formLayout.setObjectName(u'FormLayout')
|
||||||
self.backupDirectoryLabel = QtGui.QLabel(self.backupPage)
|
self.backupDirectoryLabel = QtGui.QLabel(self.backup_page)
|
||||||
self.backupDirectoryLabel.setObjectName(u'backupDirectoryLabel')
|
self.backupDirectoryLabel.setObjectName(u'backupDirectoryLabel')
|
||||||
self.backupDirectoryLayout = QtGui.QHBoxLayout()
|
self.backupDirectoryLayout = QtGui.QHBoxLayout()
|
||||||
self.backupDirectoryLayout.setObjectName(u'BackupDirectoryLayout')
|
self.backupDirectoryLayout.setObjectName(u'BackupDirectoryLayout')
|
||||||
self.backupDirectoryEdit = QtGui.QLineEdit(self.backupPage)
|
self.backupDirectoryEdit = QtGui.QLineEdit(self.backup_page)
|
||||||
self.backupDirectoryEdit.setObjectName(u'BackupFolderEdit')
|
self.backupDirectoryEdit.setObjectName(u'BackupFolderEdit')
|
||||||
self.backupDirectoryLayout.addWidget(self.backupDirectoryEdit)
|
self.backupDirectoryLayout.addWidget(self.backupDirectoryEdit)
|
||||||
self.backupBrowseButton = QtGui.QToolButton(self.backupPage)
|
self.backupBrowseButton = QtGui.QToolButton(self.backup_page)
|
||||||
self.backupBrowseButton.setIcon(self.open_icon)
|
self.backupBrowseButton.setIcon(self.open_icon)
|
||||||
self.backupBrowseButton.setObjectName(u'BackupBrowseButton')
|
self.backupBrowseButton.setObjectName(u'BackupBrowseButton')
|
||||||
self.backupDirectoryLayout.addWidget(self.backupBrowseButton)
|
self.backupDirectoryLayout.addWidget(self.backupBrowseButton)
|
||||||
self.formLayout.addRow(self.backupDirectoryLabel, self.backupDirectoryLayout)
|
self.formLayout.addRow(self.backupDirectoryLabel, self.backupDirectoryLayout)
|
||||||
self.backupLayout.addLayout(self.formLayout)
|
self.backupLayout.addLayout(self.formLayout)
|
||||||
self.noBackupCheckBox = QtGui.QCheckBox(self.backupPage)
|
self.noBackupCheckBox = QtGui.QCheckBox(self.backup_page)
|
||||||
self.noBackupCheckBox.setObjectName('NoBackupCheckBox')
|
self.noBackupCheckBox.setObjectName('NoBackupCheckBox')
|
||||||
self.backupLayout.addWidget(self.noBackupCheckBox)
|
self.backupLayout.addWidget(self.noBackupCheckBox)
|
||||||
self.spacer = QtGui.QSpacerItem(10, 0, QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Minimum)
|
self.spacer = QtGui.QSpacerItem(10, 0, QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Minimum)
|
||||||
self.backupLayout.addItem(self.spacer)
|
self.backupLayout.addItem(self.spacer)
|
||||||
self.addPage(self.backupPage)
|
self.addPage(self.backup_page)
|
||||||
# Select Page
|
# Select Page
|
||||||
self.selectPage = QtGui.QWizardPage()
|
self.selectPage = QtGui.QWizardPage()
|
||||||
self.selectPage.setObjectName(u'SelectPage')
|
self.selectPage.setObjectName(u'SelectPage')
|
||||||
|
@ -247,8 +247,8 @@ class BibleUpgradeForm(OpenLPWizard):
|
||||||
self.information_label.setText(translate('BiblesPlugin.UpgradeWizardForm',
|
self.information_label.setText(translate('BiblesPlugin.UpgradeWizardForm',
|
||||||
'This wizard will help you to upgrade your existing Bibles from a prior version of OpenLP 2. '
|
'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.'))
|
'Click the next button below to start the upgrade process.'))
|
||||||
self.backupPage.setTitle(translate('BiblesPlugin.UpgradeWizardForm', 'Select Backup Directory'))
|
self.backup_page.setTitle(translate('BiblesPlugin.UpgradeWizardForm', 'Select Backup Directory'))
|
||||||
self.backupPage.setSubTitle(translate('BiblesPlugin.UpgradeWizardForm',
|
self.backup_page.setSubTitle(translate('BiblesPlugin.UpgradeWizardForm',
|
||||||
'Please select a backup directory for your Bibles'))
|
'Please select a backup directory for your Bibles'))
|
||||||
self.backupInfoLabel.setText(translate('BiblesPlugin.UpgradeWizardForm',
|
self.backupInfoLabel.setText(translate('BiblesPlugin.UpgradeWizardForm',
|
||||||
'Previous releases of OpenLP 2.0 are unable to use upgraded Bibles.'
|
'Previous releases of OpenLP 2.0 are unable to use upgraded Bibles.'
|
||||||
|
@ -277,7 +277,7 @@ class BibleUpgradeForm(OpenLPWizard):
|
||||||
"""
|
"""
|
||||||
if self.currentPage() == self.welcome_page:
|
if self.currentPage() == self.welcome_page:
|
||||||
return True
|
return True
|
||||||
elif self.currentPage() == self.backupPage:
|
elif self.currentPage() == self.backup_page:
|
||||||
if not self.noBackupCheckBox.checkState() == QtCore.Qt.Checked:
|
if not self.noBackupCheckBox.checkState() == QtCore.Qt.Checked:
|
||||||
backup_path = self.backupDirectoryEdit.text()
|
backup_path = self.backupDirectoryEdit.text()
|
||||||
if not backup_path:
|
if not backup_path:
|
||||||
|
@ -316,7 +316,7 @@ class BibleUpgradeForm(OpenLPWizard):
|
||||||
settings.beginGroup(self.plugin.settings_section)
|
settings.beginGroup(self.plugin.settings_section)
|
||||||
self.stop_import_flag = False
|
self.stop_import_flag = False
|
||||||
self.success.clear()
|
self.success.clear()
|
||||||
self.newbibles.clear()
|
self.new_bibles.clear()
|
||||||
self.clearScrollArea()
|
self.clearScrollArea()
|
||||||
self.files = self.manager.old_bible_databases
|
self.files = self.manager.old_bible_databases
|
||||||
self.addScrollArea()
|
self.addScrollArea()
|
||||||
|
@ -329,7 +329,7 @@ class BibleUpgradeForm(OpenLPWizard):
|
||||||
self.cancel_button.setVisible(True)
|
self.cancel_button.setVisible(True)
|
||||||
settings.endGroup()
|
settings.endGroup()
|
||||||
|
|
||||||
def preWizard(self):
|
def pre_wizard(self):
|
||||||
"""
|
"""
|
||||||
Prepare the UI for the upgrade.
|
Prepare the UI for the upgrade.
|
||||||
"""
|
"""
|
||||||
|
@ -372,8 +372,8 @@ class BibleUpgradeForm(OpenLPWizard):
|
||||||
name = filename[1]
|
name = filename[1]
|
||||||
self.progress_label.setText(translate('BiblesPlugin.UpgradeWizardForm',
|
self.progress_label.setText(translate('BiblesPlugin.UpgradeWizardForm',
|
||||||
'Upgrading Bible %s of %s: "%s"\nUpgrading ...') % (number + 1, max_bibles, name))
|
'Upgrading Bible %s of %s: "%s"\nUpgrading ...') % (number + 1, max_bibles, name))
|
||||||
self.newbibles[number] = BibleDB(self.media_item, path=self.path, name=name, file=filename[0])
|
self.new_bibles[number] = BibleDB(self.media_item, path=self.path, name=name, file=filename[0])
|
||||||
self.newbibles[number].register(self.plugin.upgrade_wizard)
|
self.new_bibles[number].register(self.plugin.upgrade_wizard)
|
||||||
metadata = old_bible.get_metadata()
|
metadata = old_bible.get_metadata()
|
||||||
web_bible = False
|
web_bible = False
|
||||||
meta_data = {}
|
meta_data = {}
|
||||||
|
@ -387,7 +387,7 @@ class BibleUpgradeForm(OpenLPWizard):
|
||||||
# Copy the metadata
|
# Copy the metadata
|
||||||
meta_data[meta[u'key']] = meta[u'value']
|
meta_data[meta[u'key']] = meta[u'value']
|
||||||
if meta[u'key'] != u'name' and meta[u'key'] != u'dbversion':
|
if meta[u'key'] != u'name' and meta[u'key'] != u'dbversion':
|
||||||
self.newbibles[number].save_meta(meta[u'key'], meta[u'value'])
|
self.new_bibles[number].save_meta(meta[u'key'], meta[u'value'])
|
||||||
if meta[u'key'] == u'download_source':
|
if meta[u'key'] == u'download_source':
|
||||||
web_bible = True
|
web_bible = True
|
||||||
self.includeWebBible = True
|
self.includeWebBible = True
|
||||||
|
@ -403,8 +403,8 @@ class BibleUpgradeForm(OpenLPWizard):
|
||||||
if not books:
|
if not books:
|
||||||
log.error(u'Upgrading books from %s - download name: "%s" failed' % (
|
log.error(u'Upgrading books from %s - download name: "%s" failed' % (
|
||||||
meta_data[u'download_source'], meta_data[u'download_name']))
|
meta_data[u'download_source'], meta_data[u'download_name']))
|
||||||
self.newbibles[number].session.close()
|
self.new_bibles[number].session.close()
|
||||||
del self.newbibles[number]
|
del self.new_bibles[number]
|
||||||
critical_error_message_box(
|
critical_error_message_box(
|
||||||
translate('BiblesPlugin.UpgradeWizardForm', 'Download Error'),
|
translate('BiblesPlugin.UpgradeWizardForm', 'Download Error'),
|
||||||
translate('BiblesPlugin.UpgradeWizardForm',
|
translate('BiblesPlugin.UpgradeWizardForm',
|
||||||
|
@ -419,14 +419,14 @@ class BibleUpgradeForm(OpenLPWizard):
|
||||||
meta_data[u'download_source'].lower())
|
meta_data[u'download_source'].lower())
|
||||||
if bible and bible[u'language_id']:
|
if bible and bible[u'language_id']:
|
||||||
language_id = bible[u'language_id']
|
language_id = bible[u'language_id']
|
||||||
self.newbibles[number].save_meta(u'language_id',
|
self.new_bibles[number].save_meta(u'language_id',
|
||||||
language_id)
|
language_id)
|
||||||
else:
|
else:
|
||||||
language_id = self.newbibles[number].get_language(name)
|
language_id = self.new_bibles[number].get_language(name)
|
||||||
if not language_id:
|
if not language_id:
|
||||||
log.warn(u'Upgrading from "%s" failed' % filename[0])
|
log.warn(u'Upgrading from "%s" failed' % filename[0])
|
||||||
self.newbibles[number].session.close()
|
self.new_bibles[number].session.close()
|
||||||
del self.newbibles[number]
|
del self.new_bibles[number]
|
||||||
self.increment_progress_bar(translate('BiblesPlugin.UpgradeWizardForm',
|
self.increment_progress_bar(translate('BiblesPlugin.UpgradeWizardForm',
|
||||||
'Upgrading Bible %s of %s: "%s"\nFailed') % (number + 1, max_bibles, name),
|
'Upgrading Bible %s of %s: "%s"\nFailed') % (number + 1, max_bibles, name),
|
||||||
self.progress_bar.maximum() - self.progress_bar.value())
|
self.progress_bar.maximum() - self.progress_bar.value())
|
||||||
|
@ -439,17 +439,17 @@ class BibleUpgradeForm(OpenLPWizard):
|
||||||
break
|
break
|
||||||
self.increment_progress_bar(translate('BiblesPlugin.UpgradeWizardForm',
|
self.increment_progress_bar(translate('BiblesPlugin.UpgradeWizardForm',
|
||||||
'Upgrading Bible %s of %s: "%s"\nUpgrading %s ...') % (number + 1, max_bibles, name, book))
|
'Upgrading Bible %s of %s: "%s"\nUpgrading %s ...') % (number + 1, max_bibles, name, book))
|
||||||
book_ref_id = self.newbibles[number].\
|
book_ref_id = self.new_bibles[number].\
|
||||||
get_book_ref_id_by_name(book, len(books), language_id)
|
get_book_ref_id_by_name(book, len(books), language_id)
|
||||||
if not book_ref_id:
|
if not book_ref_id:
|
||||||
log.warn(u'Upgrading books from %s - download name: "%s" aborted by user' % (
|
log.warn(u'Upgrading books from %s - download name: "%s" aborted by user' % (
|
||||||
meta_data[u'download_source'], meta_data[u'download_name']))
|
meta_data[u'download_source'], meta_data[u'download_name']))
|
||||||
self.newbibles[number].session.close()
|
self.new_bibles[number].session.close()
|
||||||
del self.newbibles[number]
|
del self.new_bibles[number]
|
||||||
self.success[number] = False
|
self.success[number] = False
|
||||||
break
|
break
|
||||||
book_details = BiblesResourcesDB.get_book_by_id(book_ref_id)
|
book_details = BiblesResourcesDB.get_book_by_id(book_ref_id)
|
||||||
db_book = self.newbibles[number].create_book(book,
|
db_book = self.new_bibles[number].create_book(book,
|
||||||
book_ref_id, book_details[u'testament_id'])
|
book_ref_id, book_details[u'testament_id'])
|
||||||
# Try to import already downloaded verses.
|
# Try to import already downloaded verses.
|
||||||
oldbook = old_bible.get_book(book)
|
oldbook = old_bible.get_book(book)
|
||||||
|
@ -462,19 +462,19 @@ class BibleUpgradeForm(OpenLPWizard):
|
||||||
if self.stop_import_flag:
|
if self.stop_import_flag:
|
||||||
self.success[number] = False
|
self.success[number] = False
|
||||||
break
|
break
|
||||||
self.newbibles[number].create_verse(db_book.id,
|
self.new_bibles[number].create_verse(db_book.id,
|
||||||
int(verse[u'chapter']),
|
int(verse[u'chapter']),
|
||||||
int(verse[u'verse']), unicode(verse[u'text']))
|
int(verse[u'verse']), unicode(verse[u'text']))
|
||||||
self.application.process_events()
|
self.application.process_events()
|
||||||
self.newbibles[number].session.commit()
|
self.new_bibles[number].session.commit()
|
||||||
else:
|
else:
|
||||||
language_id = self.newbibles[number].get_object(BibleMeta, u'language_id')
|
language_id = self.new_bibles[number].get_object(BibleMeta, u'language_id')
|
||||||
if not language_id:
|
if not language_id:
|
||||||
language_id = self.newbibles[number].get_language(name)
|
language_id = self.new_bibles[number].get_language(name)
|
||||||
if not language_id:
|
if not language_id:
|
||||||
log.warn(u'Upgrading books from "%s" failed' % name)
|
log.warn(u'Upgrading books from "%s" failed' % name)
|
||||||
self.newbibles[number].session.close()
|
self.new_bibles[number].session.close()
|
||||||
del self.newbibles[number]
|
del self.new_bibles[number]
|
||||||
self.increment_progress_bar(translate('BiblesPlugin.UpgradeWizardForm',
|
self.increment_progress_bar(translate('BiblesPlugin.UpgradeWizardForm',
|
||||||
'Upgrading Bible %s of %s: "%s"\nFailed') % (number + 1, max_bibles, name),
|
'Upgrading Bible %s of %s: "%s"\nFailed') % (number + 1, max_bibles, name),
|
||||||
self.progress_bar.maximum() - self.progress_bar.value())
|
self.progress_bar.maximum() - self.progress_bar.value())
|
||||||
|
@ -489,41 +489,41 @@ class BibleUpgradeForm(OpenLPWizard):
|
||||||
self.increment_progress_bar(translate('BiblesPlugin.UpgradeWizardForm',
|
self.increment_progress_bar(translate('BiblesPlugin.UpgradeWizardForm',
|
||||||
'Upgrading Bible %s of %s: "%s"\nUpgrading %s ...') %
|
'Upgrading Bible %s of %s: "%s"\nUpgrading %s ...') %
|
||||||
(number + 1, max_bibles, name, book[u'name']))
|
(number + 1, max_bibles, name, book[u'name']))
|
||||||
book_ref_id = self.newbibles[number].get_book_ref_id_by_name(book[u'name'], len(books), language_id)
|
book_ref_id = self.new_bibles[number].get_book_ref_id_by_name(book[u'name'], len(books), language_id)
|
||||||
if not book_ref_id:
|
if not book_ref_id:
|
||||||
log.warn(u'Upgrading books from %s " failed - aborted by user' % name)
|
log.warn(u'Upgrading books from %s " failed - aborted by user' % name)
|
||||||
self.newbibles[number].session.close()
|
self.new_bibles[number].session.close()
|
||||||
del self.newbibles[number]
|
del self.new_bibles[number]
|
||||||
self.success[number] = False
|
self.success[number] = False
|
||||||
break
|
break
|
||||||
book_details = BiblesResourcesDB.get_book_by_id(book_ref_id)
|
book_details = BiblesResourcesDB.get_book_by_id(book_ref_id)
|
||||||
db_book = self.newbibles[number].create_book(book[u'name'],
|
db_book = self.new_bibles[number].create_book(book[u'name'],
|
||||||
book_ref_id, book_details[u'testament_id'])
|
book_ref_id, book_details[u'testament_id'])
|
||||||
verses = old_bible.get_verses(book[u'id'])
|
verses = old_bible.get_verses(book[u'id'])
|
||||||
if not verses:
|
if not verses:
|
||||||
log.warn(u'No verses found to import for book "%s"', book[u'name'])
|
log.warn(u'No verses found to import for book "%s"', book[u'name'])
|
||||||
self.newbibles[number].delete_book(db_book)
|
self.new_bibles[number].delete_book(db_book)
|
||||||
continue
|
continue
|
||||||
for verse in verses:
|
for verse in verses:
|
||||||
if self.stop_import_flag:
|
if self.stop_import_flag:
|
||||||
self.success[number] = False
|
self.success[number] = False
|
||||||
break
|
break
|
||||||
self.newbibles[number].create_verse(db_book.id,
|
self.new_bibles[number].create_verse(db_book.id,
|
||||||
int(verse[u'chapter']),
|
int(verse[u'chapter']),
|
||||||
int(verse[u'verse']), unicode(verse[u'text']))
|
int(verse[u'verse']), unicode(verse[u'text']))
|
||||||
self.application.process_events()
|
self.application.process_events()
|
||||||
self.newbibles[number].session.commit()
|
self.new_bibles[number].session.commit()
|
||||||
if not self.success.get(number, True):
|
if not self.success.get(number, True):
|
||||||
self.increment_progress_bar(translate('BiblesPlugin.UpgradeWizardForm',
|
self.increment_progress_bar(translate('BiblesPlugin.UpgradeWizardForm',
|
||||||
'Upgrading Bible %s of %s: "%s"\nFailed') % (number + 1, max_bibles, name),
|
'Upgrading Bible %s of %s: "%s"\nFailed') % (number + 1, max_bibles, name),
|
||||||
self.progress_bar.maximum() - self.progress_bar.value())
|
self.progress_bar.maximum() - self.progress_bar.value())
|
||||||
else:
|
else:
|
||||||
self.success[number] = True
|
self.success[number] = True
|
||||||
self.newbibles[number].save_meta(u'name', name)
|
self.new_bibles[number].save_meta(u'name', name)
|
||||||
self.increment_progress_bar(translate('BiblesPlugin.UpgradeWizardForm',
|
self.increment_progress_bar(translate('BiblesPlugin.UpgradeWizardForm',
|
||||||
'Upgrading Bible %s of %s: "%s"\nComplete') % (number + 1, max_bibles, name))
|
'Upgrading Bible %s of %s: "%s"\nComplete') % (number + 1, max_bibles, name))
|
||||||
if number in self.newbibles:
|
if number in self.new_bibles:
|
||||||
self.newbibles[number].session.close()
|
self.new_bibles[number].session.close()
|
||||||
# Close the last bible's connection if possible.
|
# Close the last bible's connection if possible.
|
||||||
if old_bible is not None:
|
if old_bible is not None:
|
||||||
old_bible.close_connection()
|
old_bible.close_connection()
|
||||||
|
|
|
@ -33,66 +33,66 @@ from openlp.core.lib import translate
|
||||||
from openlp.core.lib.ui import create_button_box
|
from openlp.core.lib.ui import create_button_box
|
||||||
|
|
||||||
class Ui_BookNameDialog(object):
|
class Ui_BookNameDialog(object):
|
||||||
def setupUi(self, bookNameDialog):
|
def setupUi(self, book_name_dialog):
|
||||||
bookNameDialog.setObjectName(u'bookNameDialog')
|
book_name_dialog.setObjectName(u'book_name_dialog')
|
||||||
bookNameDialog.resize(400, 271)
|
book_name_dialog.resize(400, 271)
|
||||||
self.bookNameLayout = QtGui.QVBoxLayout(bookNameDialog)
|
self.book_name_layout = QtGui.QVBoxLayout(book_name_dialog)
|
||||||
self.bookNameLayout.setSpacing(8)
|
self.book_name_layout.setSpacing(8)
|
||||||
self.bookNameLayout.setMargin(8)
|
self.book_name_layout.setMargin(8)
|
||||||
self.bookNameLayout.setObjectName(u'bookNameLayout')
|
self.book_name_layout.setObjectName(u'book_name_layout')
|
||||||
self.infoLabel = QtGui.QLabel(bookNameDialog)
|
self.info_label = QtGui.QLabel(book_name_dialog)
|
||||||
self.infoLabel.setWordWrap(True)
|
self.info_label.setWordWrap(True)
|
||||||
self.infoLabel.setObjectName(u'infoLabel')
|
self.info_label.setObjectName(u'info_label')
|
||||||
self.bookNameLayout.addWidget(self.infoLabel)
|
self.book_name_layout.addWidget(self.info_label)
|
||||||
self.correspondingLayout = QtGui.QGridLayout()
|
self.corresponding_layout = QtGui.QGridLayout()
|
||||||
self.correspondingLayout.setColumnStretch(1, 1)
|
self.corresponding_layout.setColumnStretch(1, 1)
|
||||||
self.correspondingLayout.setSpacing(8)
|
self.corresponding_layout.setSpacing(8)
|
||||||
self.correspondingLayout.setObjectName(u'correspondingLayout')
|
self.corresponding_layout.setObjectName(u'corresponding_layout')
|
||||||
self.currentLabel = QtGui.QLabel(bookNameDialog)
|
self.currentLabel = QtGui.QLabel(book_name_dialog)
|
||||||
self.currentLabel.setObjectName(u'currentLabel')
|
self.currentLabel.setObjectName(u'currentLabel')
|
||||||
self.correspondingLayout.addWidget(self.currentLabel, 0, 0, 1, 1)
|
self.corresponding_layout.addWidget(self.currentLabel, 0, 0, 1, 1)
|
||||||
self.currentBookLabel = QtGui.QLabel(bookNameDialog)
|
self.current_book_label = QtGui.QLabel(book_name_dialog)
|
||||||
self.currentBookLabel.setObjectName(u'currentBookLabel')
|
self.current_book_label.setObjectName(u'current_book_label')
|
||||||
self.correspondingLayout.addWidget(self.currentBookLabel, 0, 1, 1, 1)
|
self.corresponding_layout.addWidget(self.current_book_label, 0, 1, 1, 1)
|
||||||
self.correspondingLabel = QtGui.QLabel(bookNameDialog)
|
self.correspondingLabel = QtGui.QLabel(book_name_dialog)
|
||||||
self.correspondingLabel.setObjectName(u'correspondingLabel')
|
self.correspondingLabel.setObjectName(u'correspondingLabel')
|
||||||
self.correspondingLayout.addWidget(self.correspondingLabel, 1, 0, 1, 1)
|
self.corresponding_layout.addWidget(self.correspondingLabel, 1, 0, 1, 1)
|
||||||
self.correspondingComboBox = QtGui.QComboBox(bookNameDialog)
|
self.corresponding_combo_box = QtGui.QComboBox(book_name_dialog)
|
||||||
self.correspondingComboBox.setObjectName(u'correspondingComboBox')
|
self.corresponding_combo_box.setObjectName(u'corresponding_combo_box')
|
||||||
self.correspondingLayout.addWidget(self.correspondingComboBox, 1, 1, 1, 1)
|
self.corresponding_layout.addWidget(self.corresponding_combo_box, 1, 1, 1, 1)
|
||||||
self.bookNameLayout.addLayout(self.correspondingLayout)
|
self.book_name_layout.addLayout(self.corresponding_layout)
|
||||||
self.optionsGroupBox = QtGui.QGroupBox(bookNameDialog)
|
self.options_group_box = QtGui.QGroupBox(book_name_dialog)
|
||||||
self.optionsGroupBox.setObjectName(u'optionsGroupBox')
|
self.options_group_box.setObjectName(u'options_group_box')
|
||||||
self.optionsLayout = QtGui.QVBoxLayout(self.optionsGroupBox)
|
self.options_layout = QtGui.QVBoxLayout(self.options_group_box)
|
||||||
self.optionsLayout.setSpacing(8)
|
self.options_layout.setSpacing(8)
|
||||||
self.optionsLayout.setMargin(8)
|
self.options_layout.setMargin(8)
|
||||||
self.optionsLayout.setObjectName(u'optionsLayout')
|
self.options_layout.setObjectName(u'options_layout')
|
||||||
self.oldTestamentCheckBox = QtGui.QCheckBox(self.optionsGroupBox)
|
self.old_testament_check_box = QtGui.QCheckBox(self.options_group_box)
|
||||||
self.oldTestamentCheckBox.setObjectName(u'oldTestamentCheckBox')
|
self.old_testament_check_box.setObjectName(u'old_testament_check_box')
|
||||||
self.oldTestamentCheckBox.setCheckState(QtCore.Qt.Checked)
|
self.old_testament_check_box.setCheckState(QtCore.Qt.Checked)
|
||||||
self.optionsLayout.addWidget(self.oldTestamentCheckBox)
|
self.options_layout.addWidget(self.old_testament_check_box)
|
||||||
self.newTestamentCheckBox = QtGui.QCheckBox(self.optionsGroupBox)
|
self.new_testament_check_box = QtGui.QCheckBox(self.options_group_box)
|
||||||
self.newTestamentCheckBox.setObjectName(u'newTestamentCheckBox')
|
self.new_testament_check_box.setObjectName(u'new_testament_check_box')
|
||||||
self.newTestamentCheckBox.setCheckState(QtCore.Qt.Checked)
|
self.new_testament_check_box.setCheckState(QtCore.Qt.Checked)
|
||||||
self.optionsLayout.addWidget(self.newTestamentCheckBox)
|
self.options_layout.addWidget(self.new_testament_check_box)
|
||||||
self.apocryphaCheckBox = QtGui.QCheckBox(self.optionsGroupBox)
|
self.apocrypha_check_box = QtGui.QCheckBox(self.options_group_box)
|
||||||
self.apocryphaCheckBox.setObjectName(u'apocryphaCheckBox')
|
self.apocrypha_check_box.setObjectName(u'apocrypha_check_box')
|
||||||
self.apocryphaCheckBox.setCheckState(QtCore.Qt.Checked)
|
self.apocrypha_check_box.setCheckState(QtCore.Qt.Checked)
|
||||||
self.optionsLayout.addWidget(self.apocryphaCheckBox)
|
self.options_layout.addWidget(self.apocrypha_check_box)
|
||||||
self.bookNameLayout.addWidget(self.optionsGroupBox)
|
self.book_name_layout.addWidget(self.options_group_box)
|
||||||
self.button_box = create_button_box(bookNameDialog, u'button_box', [u'cancel', u'ok'])
|
self.button_box = create_button_box(book_name_dialog, u'button_box', [u'cancel', u'ok'])
|
||||||
self.bookNameLayout.addWidget(self.button_box)
|
self.book_name_layout.addWidget(self.button_box)
|
||||||
|
|
||||||
self.retranslateUi(bookNameDialog)
|
self.retranslateUi(book_name_dialog)
|
||||||
|
|
||||||
def retranslateUi(self, bookNameDialog):
|
def retranslateUi(self, book_name_dialog):
|
||||||
bookNameDialog.setWindowTitle(translate('BiblesPlugin.BookNameDialog', 'Select Book Name'))
|
book_name_dialog.setWindowTitle(translate('BiblesPlugin.BookNameDialog', 'Select Book Name'))
|
||||||
self.infoLabel.setText(translate('BiblesPlugin.BookNameDialog',
|
self.info_label.setText(translate('BiblesPlugin.BookNameDialog',
|
||||||
'The following book name cannot be matched up internally. '
|
'The following book name cannot be matched up internally. '
|
||||||
'Please select the corresponding name from the list.'))
|
'Please select the corresponding name from the list.'))
|
||||||
self.currentLabel.setText(translate('BiblesPlugin.BookNameDialog', 'Current name:'))
|
self.currentLabel.setText(translate('BiblesPlugin.BookNameDialog', 'Current name:'))
|
||||||
self.correspondingLabel.setText(translate('BiblesPlugin.BookNameDialog', 'Corresponding name:'))
|
self.correspondingLabel.setText(translate('BiblesPlugin.BookNameDialog', 'Corresponding name:'))
|
||||||
self.optionsGroupBox.setTitle(translate('BiblesPlugin.BookNameDialog', 'Show Books From'))
|
self.options_group_box.setTitle(translate('BiblesPlugin.BookNameDialog', 'Show Books From'))
|
||||||
self.oldTestamentCheckBox.setText(translate('BiblesPlugin.BookNameDialog', 'Old Testament'))
|
self.old_testament_check_box.setText(translate('BiblesPlugin.BookNameDialog', 'Old Testament'))
|
||||||
self.newTestamentCheckBox.setText(translate('BiblesPlugin.BookNameDialog', 'New Testament'))
|
self.new_testament_check_box.setText(translate('BiblesPlugin.BookNameDialog', 'New Testament'))
|
||||||
self.apocryphaCheckBox.setText(translate('BiblesPlugin.BookNameDialog', 'Apocrypha'))
|
self.apocrypha_check_box.setText(translate('BiblesPlugin.BookNameDialog', 'Apocrypha'))
|
||||||
|
|
|
@ -66,61 +66,61 @@ class BookNameForm(QDialog, Ui_BookNameDialog):
|
||||||
"""
|
"""
|
||||||
Set up the signals used in the booknameform.
|
Set up the signals used in the booknameform.
|
||||||
"""
|
"""
|
||||||
self.oldTestamentCheckBox.stateChanged.connect(self.onCheckBoxIndexChanged)
|
self.old_testament_check_box.stateChanged.connect(self.onCheckBoxIndexChanged)
|
||||||
self.newTestamentCheckBox.stateChanged.connect(self.onCheckBoxIndexChanged)
|
self.new_testament_check_box.stateChanged.connect(self.onCheckBoxIndexChanged)
|
||||||
self.apocryphaCheckBox.stateChanged.connect(self.onCheckBoxIndexChanged)
|
self.apocrypha_check_box.stateChanged.connect(self.onCheckBoxIndexChanged)
|
||||||
|
|
||||||
def onCheckBoxIndexChanged(self, index):
|
def onCheckBoxIndexChanged(self, index):
|
||||||
"""
|
"""
|
||||||
Reload Combobox if CheckBox state has changed
|
Reload Combobox if CheckBox state has changed
|
||||||
"""
|
"""
|
||||||
self.reloadComboBox()
|
self.reload_combo_box()
|
||||||
|
|
||||||
def reloadComboBox(self):
|
def reload_combo_box(self):
|
||||||
"""
|
"""
|
||||||
Reload the Combobox items
|
Reload the Combobox items
|
||||||
"""
|
"""
|
||||||
self.correspondingComboBox.clear()
|
self.corresponding_combo_box.clear()
|
||||||
items = BiblesResourcesDB.get_books()
|
items = BiblesResourcesDB.get_books()
|
||||||
for item in items:
|
for item in items:
|
||||||
addBook = True
|
add_book = True
|
||||||
for book in self.books:
|
for book in self.books:
|
||||||
if book.book_reference_id == item[u'id']:
|
if book.book_reference_id == item[u'id']:
|
||||||
addBook = False
|
add_book = False
|
||||||
break
|
break
|
||||||
if self.oldTestamentCheckBox.checkState() == QtCore.Qt.Unchecked and item[u'testament_id'] == 1:
|
if self.old_testament_check_box.checkState() == QtCore.Qt.Unchecked and item[u'testament_id'] == 1:
|
||||||
addBook = False
|
add_book = False
|
||||||
elif self.newTestamentCheckBox.checkState() == QtCore.Qt.Unchecked and item[u'testament_id'] == 2:
|
elif self.new_testament_check_box.checkState() == QtCore.Qt.Unchecked and item[u'testament_id'] == 2:
|
||||||
addBook = False
|
add_book = False
|
||||||
elif self.apocryphaCheckBox.checkState() == QtCore.Qt.Unchecked and item[u'testament_id'] == 3:
|
elif self.apocrypha_check_box.checkState() == QtCore.Qt.Unchecked and item[u'testament_id'] == 3:
|
||||||
addBook = False
|
add_book = False
|
||||||
if addBook:
|
if add_book:
|
||||||
self.correspondingComboBox.addItem(self.book_names[item[u'abbreviation']])
|
self.corresponding_combo_box.addItem(self.book_names[item[u'abbreviation']])
|
||||||
|
|
||||||
def exec_(self, name, books, maxbooks):
|
def exec_(self, name, books, max_books):
|
||||||
self.books = books
|
self.books = books
|
||||||
log.debug(maxbooks)
|
log.debug(max_books)
|
||||||
if maxbooks <= 27:
|
if max_books <= 27:
|
||||||
self.oldTestamentCheckBox.setCheckState(QtCore.Qt.Unchecked)
|
self.old_testament_check_box.setCheckState(QtCore.Qt.Unchecked)
|
||||||
self.apocryphaCheckBox.setCheckState(QtCore.Qt.Unchecked)
|
self.apocrypha_check_box.setCheckState(QtCore.Qt.Unchecked)
|
||||||
elif maxbooks <= 66:
|
elif max_books <= 66:
|
||||||
self.apocryphaCheckBox.setCheckState(QtCore.Qt.Unchecked)
|
self.apocrypha_check_box.setCheckState(QtCore.Qt.Unchecked)
|
||||||
self.reloadComboBox()
|
self.reload_combo_box()
|
||||||
self.currentBookLabel.setText(unicode(name))
|
self.current_book_label.setText(unicode(name))
|
||||||
self.correspondingComboBox.setFocus()
|
self.corresponding_combo_box.setFocus()
|
||||||
return QDialog.exec_(self)
|
return QDialog.exec_(self)
|
||||||
|
|
||||||
def accept(self):
|
def accept(self):
|
||||||
if self.correspondingComboBox.currentText() == u'':
|
if not self.corresponding_combo_box.currentText():
|
||||||
critical_error_message_box(message=translate('BiblesPlugin.BookNameForm', 'You need to select a book.'))
|
critical_error_message_box(message=translate('BiblesPlugin.BookNameForm', 'You need to select a book.'))
|
||||||
self.correspondingComboBox.setFocus()
|
self.corresponding_combo_box.setFocus()
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
cor_book = self.correspondingComboBox.currentText()
|
cor_book = self.corresponding_combo_box.currentText()
|
||||||
for character in u'\\.^$*+?{}[]()':
|
for character in u'\\.^$*+?{}[]()':
|
||||||
cor_book = cor_book.replace(character, u'\\' + character)
|
cor_book = cor_book.replace(character, u'\\' + character)
|
||||||
books = filter(lambda key:
|
books = filter(
|
||||||
re.match(cor_book, unicode(self.book_names[key]), re.UNICODE), self.book_names.keys())
|
lambda key: re.match(cor_book, unicode(self.book_names[key]), re.UNICODE), self.book_names.keys())
|
||||||
books = filter(None, map(BiblesResourcesDB.get_book, books))
|
books = filter(None, map(BiblesResourcesDB.get_book, books))
|
||||||
if books:
|
if books:
|
||||||
self.book_id = books[0][u'id']
|
self.book_id = books[0][u'id']
|
||||||
|
|
|
@ -36,118 +36,118 @@ from openlp.plugins.bibles.lib.db import BiblesResourcesDB
|
||||||
|
|
||||||
|
|
||||||
class Ui_EditBibleDialog(object):
|
class Ui_EditBibleDialog(object):
|
||||||
def setupUi(self, editBibleDialog):
|
def setupUi(self, edit_bible_dialog):
|
||||||
editBibleDialog.setObjectName(u'editBibleDialog')
|
edit_bible_dialog.setObjectName(u'edit_bible_dialog')
|
||||||
editBibleDialog.resize(520, 400)
|
edit_bible_dialog.resize(520, 400)
|
||||||
editBibleDialog.setWindowIcon(build_icon(u':/icon/openlp-logo-16x16.png'))
|
edit_bible_dialog.setWindowIcon(build_icon(u':/icon/openlp-logo-16x16.png'))
|
||||||
editBibleDialog.setModal(True)
|
edit_bible_dialog.setModal(True)
|
||||||
self.dialogLayout = QtGui.QVBoxLayout(editBibleDialog)
|
self.dialog_layout = QtGui.QVBoxLayout(edit_bible_dialog)
|
||||||
self.dialogLayout.setSpacing(8)
|
self.dialog_layout.setSpacing(8)
|
||||||
self.dialogLayout.setContentsMargins(8, 8, 8, 8)
|
self.dialog_layout.setContentsMargins(8, 8, 8, 8)
|
||||||
self.dialogLayout.setObjectName(u'dialog_layout')
|
self.dialog_layout.setObjectName(u'dialog_layout')
|
||||||
self.bibleTabWidget = QtGui.QTabWidget(editBibleDialog)
|
self.bible_tab_widget = QtGui.QTabWidget(edit_bible_dialog)
|
||||||
self.bibleTabWidget.setObjectName(u'BibleTabWidget')
|
self.bible_tab_widget.setObjectName(u'BibleTabWidget')
|
||||||
# Meta tab
|
# Meta tab
|
||||||
self.metaTab = QtGui.QWidget()
|
self.meta_tab = QtGui.QWidget()
|
||||||
self.metaTab.setObjectName(u'metaTab')
|
self.meta_tab.setObjectName(u'meta_tab')
|
||||||
self.metaTabLayout = QtGui.QVBoxLayout(self.metaTab)
|
self.meta_tab_layout = QtGui.QVBoxLayout(self.meta_tab)
|
||||||
self.metaTabLayout.setObjectName(u'metaTabLayout')
|
self.meta_tab_layout.setObjectName(u'meta_tab_layout')
|
||||||
self.licenseDetailsGroupBox = QtGui.QGroupBox(self.metaTab)
|
self.license_details_group_box = QtGui.QGroupBox(self.meta_tab)
|
||||||
self.licenseDetailsGroupBox.setObjectName(u'licenseDetailsGroupBox')
|
self.license_details_group_box.setObjectName(u'license_details_group_box')
|
||||||
self.licenseDetailsLayout = QtGui.QFormLayout(self.licenseDetailsGroupBox)
|
self.license_details_layout = QtGui.QFormLayout(self.license_details_group_box)
|
||||||
self.licenseDetailsLayout.setObjectName(u'licenseDetailsLayout')
|
self.license_details_layout.setObjectName(u'license_details_layout')
|
||||||
self.versionNameLabel = QtGui.QLabel(self.licenseDetailsGroupBox)
|
self.version_name_label = QtGui.QLabel(self.license_details_group_box)
|
||||||
self.versionNameLabel.setObjectName(u'versionNameLabel')
|
self.version_name_label.setObjectName(u'version_name_label')
|
||||||
self.versionNameEdit = QtGui.QLineEdit(self.licenseDetailsGroupBox)
|
self.version_name_edit = QtGui.QLineEdit(self.license_details_group_box)
|
||||||
self.versionNameEdit.setObjectName(u'versionNameEdit')
|
self.version_name_edit.setObjectName(u'version_name_edit')
|
||||||
self.versionNameLabel.setBuddy(self.versionNameEdit)
|
self.version_name_label.setBuddy(self.version_name_edit)
|
||||||
self.licenseDetailsLayout.addRow(self.versionNameLabel, self.versionNameEdit)
|
self.license_details_layout.addRow(self.version_name_label, self.version_name_edit)
|
||||||
self.copyrightLabel = QtGui.QLabel(self.licenseDetailsGroupBox)
|
self.copyright_label = QtGui.QLabel(self.license_details_group_box)
|
||||||
self.copyrightLabel.setObjectName(u'copyrightLabel')
|
self.copyright_label.setObjectName(u'copyright_label')
|
||||||
self.copyrightEdit = QtGui.QLineEdit(self.licenseDetailsGroupBox)
|
self.copyright_edit = QtGui.QLineEdit(self.license_details_group_box)
|
||||||
self.copyrightEdit.setObjectName(u'copyright_edit')
|
self.copyright_edit.setObjectName(u'copyright_edit')
|
||||||
self.copyrightLabel.setBuddy(self.copyrightEdit)
|
self.copyright_label.setBuddy(self.copyright_edit)
|
||||||
self.licenseDetailsLayout.addRow(self.copyrightLabel, self.copyrightEdit)
|
self.license_details_layout.addRow(self.copyright_label, self.copyright_edit)
|
||||||
self.permissionsLabel = QtGui.QLabel(self.licenseDetailsGroupBox)
|
self.permissions_label = QtGui.QLabel(self.license_details_group_box)
|
||||||
self.permissionsLabel.setObjectName(u'permissionsLabel')
|
self.permissions_label.setObjectName(u'permissions_label')
|
||||||
self.permissionsEdit = QtGui.QLineEdit(self.licenseDetailsGroupBox)
|
self.permissions_edit = QtGui.QLineEdit(self.license_details_group_box)
|
||||||
self.permissionsEdit.setObjectName(u'permissionsEdit')
|
self.permissions_edit.setObjectName(u'permissions_edit')
|
||||||
self.permissionsLabel.setBuddy(self.permissionsEdit)
|
self.permissions_label.setBuddy(self.permissions_edit)
|
||||||
self.licenseDetailsLayout.addRow(self.permissionsLabel, self.permissionsEdit)
|
self.license_details_layout.addRow(self.permissions_label, self.permissions_edit)
|
||||||
self.metaTabLayout.addWidget(self.licenseDetailsGroupBox)
|
self.meta_tab_layout.addWidget(self.license_details_group_box)
|
||||||
self.languageSelectionGroupBox = QtGui.QGroupBox(self.metaTab)
|
self.language_selection_group_box = QtGui.QGroupBox(self.meta_tab)
|
||||||
self.languageSelectionGroupBox.setObjectName(u'languageSelectionGroupBox')
|
self.language_selection_group_box.setObjectName(u'language_selection_group_box')
|
||||||
self.languageSelectionLayout = QtGui.QVBoxLayout(self.languageSelectionGroupBox)
|
self.language_selection_layout = QtGui.QVBoxLayout(self.language_selection_group_box)
|
||||||
self.languageSelectionLabel = QtGui.QLabel(self.languageSelectionGroupBox)
|
self.language_selection_label = QtGui.QLabel(self.language_selection_group_box)
|
||||||
self.languageSelectionLabel.setObjectName(u'languageSelectionLabel')
|
self.language_selection_label.setObjectName(u'language_selection_label')
|
||||||
self.languageSelectionComboBox = QtGui.QComboBox(self.languageSelectionGroupBox)
|
self.language_selection_combo_box = QtGui.QComboBox(self.language_selection_group_box)
|
||||||
self.languageSelectionComboBox.setObjectName(u'languageSelectionComboBox')
|
self.language_selection_combo_box.setObjectName(u'language_selection_combo_box')
|
||||||
self.languageSelectionComboBox.addItems([u'', u'', u'', u''])
|
self.language_selection_combo_box.addItems([u'', u'', u'', u''])
|
||||||
self.languageSelectionLayout.addWidget(self.languageSelectionLabel)
|
self.language_selection_layout.addWidget(self.language_selection_label)
|
||||||
self.languageSelectionLayout.addWidget(self.languageSelectionComboBox)
|
self.language_selection_layout.addWidget(self.language_selection_combo_box)
|
||||||
self.metaTabLayout.addWidget(self.languageSelectionGroupBox)
|
self.meta_tab_layout.addWidget(self.language_selection_group_box)
|
||||||
self.metaTabLayout.addStretch()
|
self.meta_tab_layout.addStretch()
|
||||||
self.bibleTabWidget.addTab(self.metaTab, u'')
|
self.bible_tab_widget.addTab(self.meta_tab, u'')
|
||||||
# Book name tab
|
# Book name tab
|
||||||
self.bookNameTab = QtGui.QWidget()
|
self.book_name_tab = QtGui.QWidget()
|
||||||
self.bookNameTab.setObjectName(u'bookNameTab')
|
self.book_name_tab.setObjectName(u'book_name_tab')
|
||||||
self.bookNameTabLayout = QtGui.QVBoxLayout(self.bookNameTab)
|
self.book_name_tab_layout = QtGui.QVBoxLayout(self.book_name_tab)
|
||||||
self.bookNameTabLayout.setObjectName(u'bookNameTabLayout')
|
self.book_name_tab_layout.setObjectName(u'book_name_tab_layout')
|
||||||
self.bookNameNotice = QtGui.QLabel(self.bookNameTab)
|
self.book_name_notice = QtGui.QLabel(self.book_name_tab)
|
||||||
self.bookNameNotice.setObjectName(u'bookNameNotice')
|
self.book_name_notice.setObjectName(u'book_name_notice')
|
||||||
self.bookNameNotice.setWordWrap(True)
|
self.book_name_notice.setWordWrap(True)
|
||||||
self.bookNameTabLayout.addWidget(self.bookNameNotice)
|
self.book_name_tab_layout.addWidget(self.book_name_notice)
|
||||||
self.scrollArea = QtGui.QScrollArea(self.bookNameTab)
|
self.scroll_area = QtGui.QScrollArea(self.book_name_tab)
|
||||||
self.scrollArea.setWidgetResizable(True)
|
self.scroll_area.setWidgetResizable(True)
|
||||||
self.scrollArea.setObjectName(u'scrollArea')
|
self.scroll_area.setObjectName(u'scroll_area')
|
||||||
self.scrollArea.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
|
self.scroll_area.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
|
||||||
self.bookNameWidget = QtGui.QWidget(self.scrollArea)
|
self.book_name_widget = QtGui.QWidget(self.scroll_area)
|
||||||
self.bookNameWidget.setObjectName(u'bookNameWidget')
|
self.book_name_widget.setObjectName(u'book_name_widget')
|
||||||
self.bookNameWidgetLayout = QtGui.QFormLayout(self.bookNameWidget)
|
self.book_name_widget_layout = QtGui.QFormLayout(self.book_name_widget)
|
||||||
self.bookNameWidgetLayout.setObjectName(u'bookNameWidgetLayout')
|
self.book_name_widget_layout.setObjectName(u'book_name_widget_layout')
|
||||||
self.bookNameLabel = {}
|
self.book_name_label = {}
|
||||||
self.bookNameEdit= {}
|
self.book_name_edit= {}
|
||||||
for book in BiblesResourcesDB.get_books():
|
for book in BiblesResourcesDB.get_books():
|
||||||
self.bookNameLabel[book[u'abbreviation']] = QtGui.QLabel(self.bookNameWidget)
|
self.book_name_label[book[u'abbreviation']] = QtGui.QLabel(self.book_name_widget)
|
||||||
self.bookNameLabel[book[u'abbreviation']].setObjectName(u'bookNameLabel[%s]' % book[u'abbreviation'])
|
self.book_name_label[book[u'abbreviation']].setObjectName(u'book_name_label[%s]' % book[u'abbreviation'])
|
||||||
self.bookNameEdit[book[u'abbreviation']] = QtGui.QLineEdit(self.bookNameWidget)
|
self.book_name_edit[book[u'abbreviation']] = QtGui.QLineEdit(self.book_name_widget)
|
||||||
self.bookNameEdit[book[u'abbreviation']].setObjectName(u'bookNameEdit[%s]' % book[u'abbreviation'])
|
self.book_name_edit[book[u'abbreviation']].setObjectName(u'book_name_edit[%s]' % book[u'abbreviation'])
|
||||||
self.bookNameWidgetLayout.addRow(
|
self.book_name_widget_layout.addRow(
|
||||||
self.bookNameLabel[book[u'abbreviation']],
|
self.book_name_label[book[u'abbreviation']],
|
||||||
self.bookNameEdit[book[u'abbreviation']])
|
self.book_name_edit[book[u'abbreviation']])
|
||||||
self.scrollArea.setWidget(self.bookNameWidget)
|
self.scroll_area.setWidget(self.book_name_widget)
|
||||||
self.bookNameTabLayout.addWidget(self.scrollArea)
|
self.book_name_tab_layout.addWidget(self.scroll_area)
|
||||||
self.bookNameTabLayout.addStretch()
|
self.book_name_tab_layout.addStretch()
|
||||||
self.bibleTabWidget.addTab(self.bookNameTab, u'')
|
self.bible_tab_widget.addTab(self.book_name_tab, u'')
|
||||||
# Last few bits
|
# Last few bits
|
||||||
self.dialogLayout.addWidget(self.bibleTabWidget)
|
self.dialog_layout.addWidget(self.bible_tab_widget)
|
||||||
self.button_box = create_button_box(editBibleDialog, u'button_box', [u'cancel', u'save'])
|
self.button_box = create_button_box(edit_bible_dialog, u'button_box', [u'cancel', u'save'])
|
||||||
self.dialogLayout.addWidget(self.button_box)
|
self.dialog_layout.addWidget(self.button_box)
|
||||||
self.retranslateUi(editBibleDialog)
|
self.retranslateUi(edit_bible_dialog)
|
||||||
QtCore.QMetaObject.connectSlotsByName(editBibleDialog)
|
QtCore.QMetaObject.connectSlotsByName(edit_bible_dialog)
|
||||||
|
|
||||||
def retranslateUi(self, editBibleDialog):
|
def retranslateUi(self, edit_bible_dialog):
|
||||||
self.book_names = BibleStrings().BookNames
|
self.book_names = BibleStrings().BookNames
|
||||||
editBibleDialog.setWindowTitle(translate('BiblesPlugin.EditBibleForm', 'Bible Editor'))
|
edit_bible_dialog.setWindowTitle(translate('BiblesPlugin.EditBibleForm', 'Bible Editor'))
|
||||||
# Meta tab
|
# Meta tab
|
||||||
self.bibleTabWidget.setTabText( self.bibleTabWidget.indexOf(self.metaTab),
|
self.bible_tab_widget.setTabText( self.bible_tab_widget.indexOf(self.meta_tab),
|
||||||
translate('SongsPlugin.EditBibleForm', 'Meta Data'))
|
translate('SongsPlugin.EditBibleForm', 'Meta Data'))
|
||||||
self.licenseDetailsGroupBox.setTitle(translate('BiblesPlugin.EditBibleForm', 'License Details'))
|
self.license_details_group_box.setTitle(translate('BiblesPlugin.EditBibleForm', 'License Details'))
|
||||||
self.versionNameLabel.setText(translate('BiblesPlugin.EditBibleForm', 'Version name:'))
|
self.version_name_label.setText(translate('BiblesPlugin.EditBibleForm', 'Version name:'))
|
||||||
self.copyrightLabel.setText(translate('BiblesPlugin.EditBibleForm', 'Copyright:'))
|
self.copyright_label.setText(translate('BiblesPlugin.EditBibleForm', 'Copyright:'))
|
||||||
self.permissionsLabel.setText(translate('BiblesPlugin.EditBibleForm', 'Permissions:'))
|
self.permissions_label.setText(translate('BiblesPlugin.EditBibleForm', 'Permissions:'))
|
||||||
self.languageSelectionGroupBox.setTitle(translate('BiblesPlugin.EditBibleForm', 'Default Bible Language'))
|
self.language_selection_group_box.setTitle(translate('BiblesPlugin.EditBibleForm', 'Default Bible Language'))
|
||||||
self.languageSelectionLabel.setText(translate('BiblesPlugin.EditBibleForm',
|
self.language_selection_label.setText(translate('BiblesPlugin.EditBibleForm',
|
||||||
'Book name language in search field, search results and on display:'))
|
'Book name language in search field, search results and on display:'))
|
||||||
self.languageSelectionComboBox.setItemText(0, translate('BiblesPlugin.EditBibleForm', 'Global Settings'))
|
self.language_selection_combo_box.setItemText(0, translate('BiblesPlugin.EditBibleForm', 'Global Settings'))
|
||||||
self.languageSelectionComboBox.setItemText(LanguageSelection.Bible + 1,
|
self.language_selection_combo_box.setItemText(LanguageSelection.Bible + 1,
|
||||||
translate('BiblesPlugin.EditBibleForm', 'Bible Language'))
|
translate('BiblesPlugin.EditBibleForm', 'Bible Language'))
|
||||||
self.languageSelectionComboBox.setItemText(LanguageSelection.Application + 1,
|
self.language_selection_combo_box.setItemText(LanguageSelection.Application + 1,
|
||||||
translate('BiblesPlugin.EditBibleForm', 'Application Language'))
|
translate('BiblesPlugin.EditBibleForm', 'Application Language'))
|
||||||
self.languageSelectionComboBox.setItemText(LanguageSelection.English + 1,
|
self.language_selection_combo_box.setItemText(LanguageSelection.English + 1,
|
||||||
translate('BiblesPlugin.EditBibleForm', 'English'))
|
translate('BiblesPlugin.EditBibleForm', 'English'))
|
||||||
# Book name tab
|
# Book name tab
|
||||||
self.bibleTabWidget.setTabText(self.bibleTabWidget.indexOf(self.bookNameTab),
|
self.bible_tab_widget.setTabText(self.bible_tab_widget.indexOf(self.book_name_tab),
|
||||||
translate('SongsPlugin.EditBibleForm', 'Custom Book Names'))
|
translate('SongsPlugin.EditBibleForm', 'Custom Book Names'))
|
||||||
for book in BiblesResourcesDB.get_books():
|
for book in BiblesResourcesDB.get_books():
|
||||||
self.bookNameLabel[book[u'abbreviation']].setText(u'%s:' % unicode(self.book_names[book[u'abbreviation']]))
|
self.book_name_label[book[u'abbreviation']].setText(u'%s:' % unicode(self.book_names[book[u'abbreviation']]))
|
||||||
|
|
|
@ -65,33 +65,33 @@ class EditBibleForm(QtGui.QDialog, Ui_EditBibleDialog):
|
||||||
"""
|
"""
|
||||||
log.debug(u'Load Bible')
|
log.debug(u'Load Bible')
|
||||||
self.bible = bible
|
self.bible = bible
|
||||||
self.versionNameEdit.setText(self.manager.get_meta_data(self.bible, u'name').value)
|
self.version_name_edit.setText(self.manager.get_meta_data(self.bible, u'name').value)
|
||||||
self.copyrightEdit.setText(self.manager.get_meta_data(self.bible, u'copyright').value)
|
self.copyright_edit.setText(self.manager.get_meta_data(self.bible, u'copyright').value)
|
||||||
self.permissionsEdit.setText(self.manager.get_meta_data(self.bible, u'permissions').value)
|
self.permissions_edit.setText(self.manager.get_meta_data(self.bible, u'permissions').value)
|
||||||
book_name_language = self.manager.get_meta_data(self.bible, u'book_name_language')
|
book_name_language = self.manager.get_meta_data(self.bible, u'book_name_language')
|
||||||
if book_name_language and book_name_language.value != u'None':
|
if book_name_language and book_name_language.value != u'None':
|
||||||
self.languageSelectionComboBox.setCurrentIndex(int(book_name_language.value) + 1)
|
self.language_selection_combo_box.setCurrentIndex(int(book_name_language.value) + 1)
|
||||||
self.books = {}
|
self.books = {}
|
||||||
self.webbible = self.manager.get_meta_data(self.bible, u'download_source')
|
self.webbible = self.manager.get_meta_data(self.bible, u'download_source')
|
||||||
if self.webbible:
|
if self.webbible:
|
||||||
self.bookNameNotice.setText(translate('BiblesPlugin.EditBibleForm',
|
self.book_name_notice.setText(translate('BiblesPlugin.EditBibleForm',
|
||||||
'This is a Web Download Bible.\nIt is not possible to customize the Book Names.'))
|
'This is a Web Download Bible.\nIt is not possible to customize the Book Names.'))
|
||||||
self.scrollArea.hide()
|
self.scroll_area.hide()
|
||||||
else:
|
else:
|
||||||
self.bookNameNotice.setText(translate('BiblesPlugin.EditBibleForm',
|
self.book_name_notice.setText(translate('BiblesPlugin.EditBibleForm',
|
||||||
'To use the customized book names, "Bible language" must be selected on the Meta Data tab or, '
|
'To use the customized book names, "Bible language" must be selected on the Meta Data tab or, '
|
||||||
'if "Global settings" is selected, on the Bible page in Configure OpenLP.'))
|
'if "Global settings" is selected, on the Bible page in Configure OpenLP.'))
|
||||||
for book in BiblesResourcesDB.get_books():
|
for book in BiblesResourcesDB.get_books():
|
||||||
self.books[book[u'abbreviation']] = self.manager.get_book_by_id(self.bible, book[u'id'])
|
self.books[book[u'abbreviation']] = self.manager.get_book_by_id(self.bible, book[u'id'])
|
||||||
if self.books[book[u'abbreviation']] and not self.webbible:
|
if self.books[book[u'abbreviation']] and not self.webbible:
|
||||||
self.bookNameEdit[book[u'abbreviation']].setText(self.books[book[u'abbreviation']].name)
|
self.book_name_edit[book[u'abbreviation']].setText(self.books[book[u'abbreviation']].name)
|
||||||
else:
|
else:
|
||||||
# It is necessary to remove the Widget otherwise there still
|
# It is necessary to remove the Widget otherwise there still
|
||||||
# exists the vertical spacing in QFormLayout
|
# exists the vertical spacing in QFormLayout
|
||||||
self.bookNameWidgetLayout.removeWidget(self.bookNameLabel[book[u'abbreviation']])
|
self.book_name_widget_layout.removeWidget(self.book_name_label[book[u'abbreviation']])
|
||||||
self.bookNameLabel[book[u'abbreviation']].hide()
|
self.book_name_label[book[u'abbreviation']].hide()
|
||||||
self.bookNameWidgetLayout.removeWidget(self.bookNameEdit[book[u'abbreviation']])
|
self.book_name_widget_layout.removeWidget(self.book_name_edit[book[u'abbreviation']])
|
||||||
self.bookNameEdit[book[u'abbreviation']].hide()
|
self.book_name_edit[book[u'abbreviation']].hide()
|
||||||
|
|
||||||
def reject(self):
|
def reject(self):
|
||||||
"""
|
"""
|
||||||
|
@ -106,10 +106,10 @@ class EditBibleForm(QtGui.QDialog, Ui_EditBibleDialog):
|
||||||
Exit Dialog and save data
|
Exit Dialog and save data
|
||||||
"""
|
"""
|
||||||
log.debug(u'BibleEditForm.accept')
|
log.debug(u'BibleEditForm.accept')
|
||||||
version = self.versionNameEdit.text()
|
version = self.version_name_edit.text()
|
||||||
copyright = self.copyrightEdit.text()
|
copyright = self.copyright_edit.text()
|
||||||
permissions = self.permissionsEdit.text()
|
permissions = self.permissions_edit.text()
|
||||||
book_name_language = self.languageSelectionComboBox.currentIndex() - 1
|
book_name_language = self.language_selection_combo_box.currentIndex() - 1
|
||||||
if book_name_language == -1:
|
if book_name_language == -1:
|
||||||
book_name_language = None
|
book_name_language = None
|
||||||
if not self.validateMeta(version, copyright):
|
if not self.validateMeta(version, copyright):
|
||||||
|
@ -118,7 +118,7 @@ class EditBibleForm(QtGui.QDialog, Ui_EditBibleDialog):
|
||||||
custom_names = {}
|
custom_names = {}
|
||||||
for abbr, book in self.books.iteritems():
|
for abbr, book in self.books.iteritems():
|
||||||
if book:
|
if book:
|
||||||
custom_names[abbr] = self.bookNameEdit[abbr].text()
|
custom_names[abbr] = self.book_name_edit[abbr].text()
|
||||||
if book.name != custom_names[abbr]:
|
if book.name != custom_names[abbr]:
|
||||||
if not self.validateBook(custom_names[abbr], abbr):
|
if not self.validateBook(custom_names[abbr], abbr):
|
||||||
return
|
return
|
||||||
|
@ -139,19 +139,19 @@ class EditBibleForm(QtGui.QDialog, Ui_EditBibleDialog):
|
||||||
Validate the Meta before saving.
|
Validate the Meta before saving.
|
||||||
"""
|
"""
|
||||||
if not name:
|
if not name:
|
||||||
self.versionNameEdit.setFocus()
|
self.version_name_edit.setFocus()
|
||||||
critical_error_message_box(UiStrings().EmptyField,
|
critical_error_message_box(UiStrings().EmptyField,
|
||||||
translate('BiblesPlugin.BibleEditForm', 'You need to specify a version name for your Bible.'))
|
translate('BiblesPlugin.BibleEditForm', 'You need to specify a version name for your Bible.'))
|
||||||
return False
|
return False
|
||||||
elif not copyright:
|
elif not copyright:
|
||||||
self.copyrightEdit.setFocus()
|
self.copyright_edit.setFocus()
|
||||||
critical_error_message_box(UiStrings().EmptyField,
|
critical_error_message_box(UiStrings().EmptyField,
|
||||||
translate('BiblesPlugin.BibleEditForm',
|
translate('BiblesPlugin.BibleEditForm',
|
||||||
'You need to set a copyright for your Bible. Bibles in the Public Domain need to be marked as such.'))
|
'You need to set a copyright for your Bible. Bibles in the Public Domain need to be marked as such.'))
|
||||||
return False
|
return False
|
||||||
elif self.manager.exists(name) and self.manager.get_meta_data(self.bible, u'name').value != \
|
elif self.manager.exists(name) and self.manager.get_meta_data(self.bible, u'name').value != \
|
||||||
name:
|
name:
|
||||||
self.versionNameEdit.setFocus()
|
self.version_name_edit.setFocus()
|
||||||
critical_error_message_box(translate('BiblesPlugin.BibleEditForm', 'Bible Exists'),
|
critical_error_message_box(translate('BiblesPlugin.BibleEditForm', 'Bible Exists'),
|
||||||
translate('BiblesPlugin.BibleEditForm', 'This Bible already exists. Please import '
|
translate('BiblesPlugin.BibleEditForm', 'This Bible already exists. Please import '
|
||||||
'a different Bible or first delete the existing one.'))
|
'a different Bible or first delete the existing one.'))
|
||||||
|
@ -164,13 +164,13 @@ class EditBibleForm(QtGui.QDialog, Ui_EditBibleDialog):
|
||||||
"""
|
"""
|
||||||
book_regex = re.compile(u'[\d]*[^\d]+$')
|
book_regex = re.compile(u'[\d]*[^\d]+$')
|
||||||
if not new_book_name:
|
if not new_book_name:
|
||||||
self.bookNameEdit[abbreviation].setFocus()
|
self.book_name_edit[abbreviation].setFocus()
|
||||||
critical_error_message_box(UiStrings().EmptyField,
|
critical_error_message_box(UiStrings().EmptyField,
|
||||||
translate('BiblesPlugin.BibleEditForm', 'You need to specify a book name for "%s".') %
|
translate('BiblesPlugin.BibleEditForm', 'You need to specify a book name for "%s".') %
|
||||||
self.book_names[abbreviation])
|
self.book_names[abbreviation])
|
||||||
return False
|
return False
|
||||||
elif not book_regex.match(new_book_name):
|
elif not book_regex.match(new_book_name):
|
||||||
self.bookNameEdit[abbreviation].setFocus()
|
self.book_name_edit[abbreviation].setFocus()
|
||||||
critical_error_message_box(UiStrings().EmptyField,
|
critical_error_message_box(UiStrings().EmptyField,
|
||||||
translate('BiblesPlugin.BibleEditForm',
|
translate('BiblesPlugin.BibleEditForm',
|
||||||
'The book name "%s" is not correct.\nNumbers can only be used at the beginning and must\nbe '
|
'The book name "%s" is not correct.\nNumbers can only be used at the beginning and must\nbe '
|
||||||
|
@ -180,8 +180,8 @@ class EditBibleForm(QtGui.QDialog, Ui_EditBibleDialog):
|
||||||
if book:
|
if book:
|
||||||
if abbr == abbreviation:
|
if abbr == abbreviation:
|
||||||
continue
|
continue
|
||||||
if self.bookNameEdit[abbr].text() == new_book_name:
|
if self.book_name_edit[abbr].text() == new_book_name:
|
||||||
self.bookNameEdit[abbreviation].setFocus()
|
self.book_name_edit[abbreviation].setFocus()
|
||||||
critical_error_message_box(
|
critical_error_message_box(
|
||||||
translate('BiblesPlugin.BibleEditForm', 'Duplicate Book Name'),
|
translate('BiblesPlugin.BibleEditForm', 'Duplicate Book Name'),
|
||||||
translate('BiblesPlugin.BibleEditForm', 'The Book Name "%s" has been entered more than once.')
|
translate('BiblesPlugin.BibleEditForm', 'The Book Name "%s" has been entered more than once.')
|
||||||
|
|
|
@ -33,44 +33,44 @@ from openlp.core.lib import translate
|
||||||
from openlp.core.lib.ui import create_button_box
|
from openlp.core.lib.ui import create_button_box
|
||||||
|
|
||||||
class Ui_LanguageDialog(object):
|
class Ui_LanguageDialog(object):
|
||||||
def setupUi(self, languageDialog):
|
def setupUi(self, language_dialog):
|
||||||
languageDialog.setObjectName(u'languageDialog')
|
language_dialog.setObjectName(u'language_dialog')
|
||||||
languageDialog.resize(400, 165)
|
language_dialog.resize(400, 165)
|
||||||
self.languageLayout = QtGui.QVBoxLayout(languageDialog)
|
self.language_layout = QtGui.QVBoxLayout(language_dialog)
|
||||||
self.languageLayout.setSpacing(8)
|
self.language_layout.setSpacing(8)
|
||||||
self.languageLayout.setMargin(8)
|
self.language_layout.setMargin(8)
|
||||||
self.languageLayout.setObjectName(u'languageLayout')
|
self.language_layout.setObjectName(u'language_layout')
|
||||||
self.bibleLabel = QtGui.QLabel(languageDialog)
|
self.bible_label = QtGui.QLabel(language_dialog)
|
||||||
self.bibleLabel.setObjectName(u'bibleLabel')
|
self.bible_label.setObjectName(u'bible_label')
|
||||||
self.languageLayout.addWidget(self.bibleLabel)
|
self.language_layout.addWidget(self.bible_label)
|
||||||
self.infoLabel = QtGui.QLabel(languageDialog)
|
self.info_label = QtGui.QLabel(language_dialog)
|
||||||
self.infoLabel.setWordWrap(True)
|
self.info_label.setWordWrap(True)
|
||||||
self.infoLabel.setObjectName(u'infoLabel')
|
self.info_label.setObjectName(u'info_label')
|
||||||
self.languageLayout.addWidget(self.infoLabel)
|
self.language_layout.addWidget(self.info_label)
|
||||||
self.languageHBoxLayout = QtGui.QHBoxLayout()
|
self.language_h_box_layout = QtGui.QHBoxLayout()
|
||||||
self.languageHBoxLayout.setSpacing(8)
|
self.language_h_box_layout.setSpacing(8)
|
||||||
self.languageHBoxLayout.setObjectName(u'languageHBoxLayout')
|
self.language_h_box_layout.setObjectName(u'language_h_box_layout')
|
||||||
self.languageLabel = QtGui.QLabel(languageDialog)
|
self.language_label = QtGui.QLabel(language_dialog)
|
||||||
self.languageLabel.setObjectName(u'languageLabel')
|
self.language_label.setObjectName(u'language_label')
|
||||||
self.languageHBoxLayout.addWidget(self.languageLabel)
|
self.language_h_box_layout.addWidget(self.language_label)
|
||||||
self.languageComboBox = QtGui.QComboBox(languageDialog)
|
self.language_combo_box = QtGui.QComboBox(language_dialog)
|
||||||
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.MinimumExpanding, QtGui.QSizePolicy.Fixed)
|
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.MinimumExpanding, QtGui.QSizePolicy.Fixed)
|
||||||
sizePolicy.setHorizontalStretch(0)
|
sizePolicy.setHorizontalStretch(0)
|
||||||
sizePolicy.setVerticalStretch(0)
|
sizePolicy.setVerticalStretch(0)
|
||||||
sizePolicy.setHeightForWidth(self.languageComboBox.sizePolicy().hasHeightForWidth())
|
sizePolicy.setHeightForWidth(self.language_combo_box.sizePolicy().hasHeightForWidth())
|
||||||
self.languageComboBox.setSizePolicy(sizePolicy)
|
self.language_combo_box.setSizePolicy(sizePolicy)
|
||||||
self.languageComboBox.setObjectName(u'languageComboBox')
|
self.language_combo_box.setObjectName(u'language_combo_box')
|
||||||
self.languageHBoxLayout.addWidget(self.languageComboBox)
|
self.language_h_box_layout.addWidget(self.language_combo_box)
|
||||||
self.languageLayout.addLayout(self.languageHBoxLayout)
|
self.language_layout.addLayout(self.language_h_box_layout)
|
||||||
self.button_box = create_button_box(languageDialog, u'button_box', [u'cancel', u'ok'])
|
self.button_box = create_button_box(language_dialog, u'button_box', [u'cancel', u'ok'])
|
||||||
self.languageLayout.addWidget(self.button_box)
|
self.language_layout.addWidget(self.button_box)
|
||||||
|
|
||||||
self.retranslateUi(languageDialog)
|
self.retranslateUi(language_dialog)
|
||||||
|
|
||||||
def retranslateUi(self, languageDialog):
|
def retranslateUi(self, language_dialog):
|
||||||
languageDialog.setWindowTitle(translate('BiblesPlugin.LanguageDialog', 'Select Language'))
|
language_dialog.setWindowTitle(translate('BiblesPlugin.LanguageDialog', 'Select Language'))
|
||||||
self.bibleLabel.setText(translate('BiblesPlugin.LanguageDialog', ''))
|
self.bible_label.setText(translate('BiblesPlugin.LanguageDialog', ''))
|
||||||
self.infoLabel.setText(translate('BiblesPlugin.LanguageDialog',
|
self.info_label.setText(translate('BiblesPlugin.LanguageDialog',
|
||||||
'OpenLP is unable to determine the language of this translation of the Bible. Please select the language '
|
'OpenLP is unable to determine the language of this translation of the Bible. Please select the language '
|
||||||
'from the list below.'))
|
'from the list below.'))
|
||||||
self.languageLabel.setText(translate('BiblesPlugin.LanguageDialog', 'Language:'))
|
self.language_label.setText(translate('BiblesPlugin.LanguageDialog', 'Language:'))
|
||||||
|
|
|
@ -40,8 +40,10 @@ from openlp.plugins.bibles.forms.languagedialog import \
|
||||||
Ui_LanguageDialog
|
Ui_LanguageDialog
|
||||||
from openlp.plugins.bibles.lib.db import BiblesResourcesDB
|
from openlp.plugins.bibles.lib.db import BiblesResourcesDB
|
||||||
|
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class LanguageForm(QDialog, Ui_LanguageDialog):
|
class LanguageForm(QDialog, Ui_LanguageDialog):
|
||||||
"""
|
"""
|
||||||
Class to manage a dialog which ask the user for a language.
|
Class to manage a dialog which ask the user for a language.
|
||||||
|
@ -56,19 +58,17 @@ class LanguageForm(QDialog, Ui_LanguageDialog):
|
||||||
self.setupUi(self)
|
self.setupUi(self)
|
||||||
|
|
||||||
def exec_(self, bible_name):
|
def exec_(self, bible_name):
|
||||||
self.languageComboBox.addItem(u'')
|
self.language_combo_box.addItem(u'')
|
||||||
if bible_name:
|
if bible_name:
|
||||||
self.bibleLabel.setText(unicode(bible_name))
|
self.bible_label.setText(unicode(bible_name))
|
||||||
items = BiblesResourcesDB.get_languages()
|
items = BiblesResourcesDB.get_languages()
|
||||||
self.languageComboBox.addItems([item[u'name'] for item in items])
|
self.language_combo_box.addItems([item[u'name'] for item in items])
|
||||||
return QDialog.exec_(self)
|
return QDialog.exec_(self)
|
||||||
|
|
||||||
def accept(self):
|
def accept(self):
|
||||||
if not self.languageComboBox.currentText():
|
if not self.language_combo_box.currentText():
|
||||||
critical_error_message_box(
|
critical_error_message_box(message=translate('BiblesPlugin.LanguageForm', 'You need to choose a language.'))
|
||||||
message=translate('BiblesPlugin.LanguageForm',
|
self.language_combo_box.setFocus()
|
||||||
'You need to choose a language.'))
|
|
||||||
self.languageComboBox.setFocus()
|
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
return QDialog.accept(self)
|
return QDialog.accept(self)
|
||||||
|
|
|
@ -38,9 +38,11 @@ from openlp.core.lib import Settings, translate
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
REFERENCE_MATCHES = {}
|
REFERENCE_MATCHES = {}
|
||||||
REFERENCE_SEPARATORS = {}
|
REFERENCE_SEPARATORS = {}
|
||||||
|
|
||||||
|
|
||||||
class LayoutStyle(object):
|
class LayoutStyle(object):
|
||||||
"""
|
"""
|
||||||
An enumeration for bible screen layout styles.
|
An enumeration for bible screen layout styles.
|
||||||
|
@ -62,8 +64,7 @@ class DisplayStyle(object):
|
||||||
|
|
||||||
class LanguageSelection(object):
|
class LanguageSelection(object):
|
||||||
"""
|
"""
|
||||||
An enumeration for bible bookname language.
|
An enumeration for bible bookname language. And standard strings for use throughout the bibles plugin.
|
||||||
And standard strings for use throughout the bibles plugin.
|
|
||||||
"""
|
"""
|
||||||
Bible = 0
|
Bible = 0
|
||||||
Application = 1
|
Application = 1
|
||||||
|
@ -178,8 +179,7 @@ class BibleStrings(object):
|
||||||
|
|
||||||
def update_reference_separators():
|
def update_reference_separators():
|
||||||
"""
|
"""
|
||||||
Updates separators and matches for parsing and formating scripture
|
Updates separators and matches for parsing and formating scripture references.
|
||||||
references.
|
|
||||||
"""
|
"""
|
||||||
default_separators = translate('BiblesPlugin',
|
default_separators = translate('BiblesPlugin',
|
||||||
':|v|V|verse|verses;;-|to;;,|and;;end Double-semicolon delimited separators for parsing references. '
|
':|v|V|verse|verses;;-|to;;,|and;;end Double-semicolon delimited separators for parsing references. '
|
||||||
|
@ -245,9 +245,8 @@ def get_reference_match(match_type):
|
||||||
|
|
||||||
def parse_reference(reference, bible, language_selection, book_ref_id=False):
|
def parse_reference(reference, bible, language_selection, book_ref_id=False):
|
||||||
"""
|
"""
|
||||||
This is the next generation über-awesome function that takes a person's
|
This is the next generation über-awesome function that takes a person's typed in string and converts it to a list
|
||||||
typed in string and converts it to a list of references to be queried from
|
of references to be queried from the Bible database files.
|
||||||
the Bible database files.
|
|
||||||
|
|
||||||
``reference``
|
``reference``
|
||||||
A string. The Bible reference to parse.
|
A string. The Bible reference to parse.
|
||||||
|
@ -256,16 +255,14 @@ def parse_reference(reference, bible, language_selection, book_ref_id=False):
|
||||||
A object. The Bible database object.
|
A object. The Bible database object.
|
||||||
|
|
||||||
``language_selection``
|
``language_selection``
|
||||||
An int. The language selection the user has choosen in settings
|
An int. The language selection the user has choosen in settings section.
|
||||||
section.
|
|
||||||
|
|
||||||
``book_ref_id``
|
``book_ref_id``
|
||||||
A string. The book reference id.
|
A string. The book reference id.
|
||||||
|
|
||||||
Returns ``None`` or a reference list.
|
Returns ``None`` or a reference list.
|
||||||
|
|
||||||
The reference list is a list of tuples, with each tuple structured like
|
The reference list is a list of tuples, with each tuple structured like this::
|
||||||
this::
|
|
||||||
|
|
||||||
(book, chapter, from_verse, to_verse)
|
(book, chapter, from_verse, to_verse)
|
||||||
|
|
||||||
|
@ -275,8 +272,7 @@ def parse_reference(reference, bible, language_selection, book_ref_id=False):
|
||||||
|
|
||||||
**Reference string details:**
|
**Reference string details:**
|
||||||
|
|
||||||
Each reference starts with the book name and a chapter number. These are
|
Each reference starts with the book name and a chapter number. These are both mandatory.
|
||||||
both mandatory.
|
|
||||||
|
|
||||||
* ``John 3`` refers to Gospel of John chapter 3
|
* ``John 3`` refers to Gospel of John chapter 3
|
||||||
|
|
||||||
|
@ -289,38 +285,31 @@ def parse_reference(reference, bible, language_selection, book_ref_id=False):
|
||||||
* ``John 3:16`` refers to John chapter 3 verse 16
|
* ``John 3:16`` refers to John chapter 3 verse 16
|
||||||
* ``John 3:16-4:3`` refers to John chapter 3 verse 16 to chapter 4 verse 3
|
* ``John 3:16-4:3`` refers to John chapter 3 verse 16 to chapter 4 verse 3
|
||||||
|
|
||||||
After a verse reference all further single values are treat as verse in
|
After a verse reference all further single values are treat as verse in the last selected chapter.
|
||||||
the last selected chapter.
|
|
||||||
|
|
||||||
* ``John 3:16-18`` refers to John chapter 3 verses 16 to 18
|
* ``John 3:16-18`` refers to John chapter 3 verses 16 to 18
|
||||||
|
|
||||||
After a list separator it is possible to refer to additional verses. They
|
After a list separator it is possible to refer to additional verses. They are build analog to the first ones. This
|
||||||
are build analog to the first ones. This way it is possible to define each
|
way it is possible to define each number of verse references. It is not possible to refer to verses in additional
|
||||||
number of verse references. It is not possible to refer to verses in
|
books.
|
||||||
additional books.
|
|
||||||
|
|
||||||
* ``John 3:16,18`` refers to John chapter 3 verses 16 and 18
|
* ``John 3:16,18`` refers to John chapter 3 verses 16 and 18
|
||||||
* ``John 3:16-18,20`` refers to John chapter 3 verses 16 to 18 and 20
|
* ``John 3:16-18,20`` refers to John chapter 3 verses 16 to 18 and 20
|
||||||
* ``John 3:16-18,4:1`` refers to John chapter 3 verses 16 to 18 and
|
* ``John 3:16-18,4:1`` refers to John chapter 3 verses 16 to 18 and chapter 4 verse 1
|
||||||
chapter 4 verse 1
|
|
||||||
|
|
||||||
If there is a range separator without further verse declaration the last
|
If there is a range separator without further verse declaration the last refered chapter is addressed until the end.
|
||||||
refered chapter is addressed until the end.
|
|
||||||
|
|
||||||
``range_regex`` is a regular expression which matches for verse range
|
``range_regex`` is a regular expression which matches for verse range declarations:
|
||||||
declarations:
|
|
||||||
|
|
||||||
``(?:(?P<from_chapter>[0-9]+)%(sep_v)s)?``
|
``(?:(?P<from_chapter>[0-9]+)%(sep_v)s)?``
|
||||||
It starts with a optional chapter reference ``from_chapter`` followed by
|
It starts with a optional chapter reference ``from_chapter`` followed by a verse separator.
|
||||||
a verse separator.
|
|
||||||
|
|
||||||
``(?P<from_verse>[0-9]+)``
|
``(?P<from_verse>[0-9]+)``
|
||||||
The verse reference ``from_verse`` is manditory
|
The verse reference ``from_verse`` is manditory
|
||||||
|
|
||||||
``(?P<range_to>%(sep_r)s(?:`` ... ``|%(sep_e)s)?)?``
|
``(?P<range_to>%(sep_r)s(?:`` ... ``|%(sep_e)s)?)?``
|
||||||
A ``range_to`` declaration is optional. It starts with a range separator
|
A ``range_to`` declaration is optional. It starts with a range separator and contains optional a chapter and
|
||||||
and contains optional a chapter and verse declaration or a end
|
verse declaration or a end separator.
|
||||||
separator.
|
|
||||||
|
|
||||||
``(?:(?P<to_chapter>[0-9]+)%(sep_v)s)?``
|
``(?:(?P<to_chapter>[0-9]+)%(sep_v)s)?``
|
||||||
The ``to_chapter`` reference with separator is equivalent to group 1.
|
The ``to_chapter`` reference with separator is equivalent to group 1.
|
||||||
|
@ -328,17 +317,15 @@ def parse_reference(reference, bible, language_selection, book_ref_id=False):
|
||||||
``(?P<to_verse>[0-9]+)``
|
``(?P<to_verse>[0-9]+)``
|
||||||
The ``to_verse`` reference is equivalent to group 2.
|
The ``to_verse`` reference is equivalent to group 2.
|
||||||
|
|
||||||
The full reference is matched against get_reference_match(u'full'). This
|
The full reference is matched against get_reference_match(u'full'). This regular expression looks like this:
|
||||||
regular expression looks like this:
|
|
||||||
|
|
||||||
``^\s*(?!\s)(?P<book>[\d]*[^\d]+)(?<!\s)\s*``
|
``^\s*(?!\s)(?P<book>[\d]*[^\d]+)(?<!\s)\s*``
|
||||||
The ``book`` group starts with the first non-whitespace character. There
|
The ``book`` group starts with the first non-whitespace character. There are optional leading digits followed by
|
||||||
are optional leading digits followed by non-digits. The group ends
|
non-digits. The group ends before the whitspace in front of the next digit.
|
||||||
before the whitspace in front of the next digit.
|
|
||||||
|
|
||||||
``(?P<ranges>(?:%(range_regex)s(?:%(sep_l)s(?!\s*$)|(?=\s*$)))+)\s*$``
|
``(?P<ranges>(?:%(range_regex)s(?:%(sep_l)s(?!\s*$)|(?=\s*$)))+)\s*$``
|
||||||
The second group contains all ``ranges``. This can be multiple
|
The second group contains all ``ranges``. This can be multiple declarations of range_regex separated by a list
|
||||||
declarations of range_regex separated by a list separator.
|
separator.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
log.debug(u'parse_reference("%s")', reference)
|
log.debug(u'parse_reference("%s")', reference)
|
||||||
|
|
|
@ -27,8 +27,7 @@
|
||||||
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
||||||
###############################################################################
|
###############################################################################
|
||||||
"""
|
"""
|
||||||
The :mod:`cvsbible` modules provides a facility to import bibles from a set of
|
The :mod:`cvsbible` modules provides a facility to import bibles from a set of CSV files.
|
||||||
CSV files.
|
|
||||||
|
|
||||||
The module expects two mandatory files containing the books and the verses.
|
The module expects two mandatory files containing the books and the verses.
|
||||||
|
|
||||||
|
@ -55,8 +54,7 @@ There are two acceptable formats of the verses file. They are:
|
||||||
or
|
or
|
||||||
"Genesis",1,2,"And the earth was without form, and void; and...."
|
"Genesis",1,2,"And the earth was without form, and void; and...."
|
||||||
|
|
||||||
All CSV files are expected to use a comma (',') as the delimiter and double
|
All CSV files are expected to use a comma (',') as the delimiter and double quotes ('"') as the quote symbol.
|
||||||
quotes ('"') as the quote symbol.
|
|
||||||
"""
|
"""
|
||||||
import logging
|
import logging
|
||||||
import chardet
|
import chardet
|
||||||
|
@ -65,8 +63,10 @@ import csv
|
||||||
from openlp.core.lib import translate
|
from openlp.core.lib import translate
|
||||||
from openlp.plugins.bibles.lib.db import BibleDB, BiblesResourcesDB
|
from openlp.plugins.bibles.lib.db import BibleDB, BiblesResourcesDB
|
||||||
|
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class CSVBible(BibleDB):
|
class CSVBible(BibleDB):
|
||||||
"""
|
"""
|
||||||
This class provides a specialisation for importing of CSV Bibles.
|
This class provides a specialisation for importing of CSV Bibles.
|
||||||
|
@ -75,9 +75,8 @@ class CSVBible(BibleDB):
|
||||||
|
|
||||||
def __init__(self, parent, **kwargs):
|
def __init__(self, parent, **kwargs):
|
||||||
"""
|
"""
|
||||||
Loads a Bible from a set of CSV files.
|
Loads a Bible from a set of CSV files. This class assumes the files contain all the information and a clean
|
||||||
This class assumes the files contain all the information and
|
bible is being loaded.
|
||||||
a clean bible is being loaded.
|
|
||||||
"""
|
"""
|
||||||
log.info(self.__class__.__name__)
|
log.info(self.__class__.__name__)
|
||||||
BibleDB.__init__(self, parent, **kwargs)
|
BibleDB.__init__(self, parent, **kwargs)
|
||||||
|
|
|
@ -511,7 +511,7 @@ class BibleDB(QtCore.QObject, Manager):
|
||||||
language = None
|
language = None
|
||||||
language_form = LanguageForm(self.wizard)
|
language_form = LanguageForm(self.wizard)
|
||||||
if language_form.exec_(bible_name):
|
if language_form.exec_(bible_name):
|
||||||
language = unicode(language_form.languageComboBox.currentText())
|
language = unicode(language_form.language_combo_box.currentText())
|
||||||
if not language:
|
if not language:
|
||||||
return False
|
return False
|
||||||
language = BiblesResourcesDB.get_language(language)
|
language = BiblesResourcesDB.get_language(language)
|
||||||
|
|
|
@ -27,8 +27,7 @@
|
||||||
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
||||||
###############################################################################
|
###############################################################################
|
||||||
"""
|
"""
|
||||||
The :mod:`http` module enables OpenLP to retrieve scripture from bible
|
The :mod:`http` module enables OpenLP to retrieve scripture from bible websites.
|
||||||
websites.
|
|
||||||
"""
|
"""
|
||||||
import logging
|
import logging
|
||||||
import re
|
import re
|
||||||
|
@ -36,7 +35,7 @@ import socket
|
||||||
import urllib
|
import urllib
|
||||||
from HTMLParser import HTMLParseError
|
from HTMLParser import HTMLParseError
|
||||||
|
|
||||||
from BeautifulSoup import BeautifulSoup, NavigableString, Tag
|
from bs4 import BeautifulSoup, NavigableString, Tag
|
||||||
|
|
||||||
from openlp.core.lib import Registry, translate
|
from openlp.core.lib import Registry, translate
|
||||||
from openlp.core.lib.ui import critical_error_message_box
|
from openlp.core.lib.ui import critical_error_message_box
|
||||||
|
@ -44,6 +43,9 @@ from openlp.core.utils import get_web_page
|
||||||
from openlp.plugins.bibles.lib import SearchResults
|
from openlp.plugins.bibles.lib import SearchResults
|
||||||
from openlp.plugins.bibles.lib.db import BibleDB, BiblesResourcesDB, Book
|
from openlp.plugins.bibles.lib.db import BibleDB, BiblesResourcesDB, Book
|
||||||
|
|
||||||
|
CLEANER_REGEX = re.compile(r' |<br />|\'\+\'')
|
||||||
|
FIX_PUNKCTUATION_REGEX = re.compile(r'[ ]+([.,;])')
|
||||||
|
REDUCE_SPACES_REGEX = re.compile(r'[ ]{2,}')
|
||||||
UGLY_CHARS = {
|
UGLY_CHARS = {
|
||||||
u'\u2014': u' - ',
|
u'\u2014': u' - ',
|
||||||
u'\u2018': u'\'',
|
u'\u2018': u'\'',
|
||||||
|
@ -52,9 +54,12 @@ UGLY_CHARS = {
|
||||||
u'\u201d': u'"',
|
u'\u201d': u'"',
|
||||||
u' ': u' '
|
u' ': u' '
|
||||||
}
|
}
|
||||||
|
VERSE_NUMBER_REGEX = re.compile(r'v(\d{1,2})(\d{3})(\d{3}) verse.*')
|
||||||
|
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class BGExtract(object):
|
class BGExtract(object):
|
||||||
"""
|
"""
|
||||||
Extract verses from BibleGateway
|
Extract verses from BibleGateway
|
||||||
|
@ -78,9 +83,9 @@ class BGExtract(object):
|
||||||
An HTML class attribute for further qualification.
|
An HTML class attribute for further qualification.
|
||||||
"""
|
"""
|
||||||
if class_:
|
if class_:
|
||||||
all_tags = parent.findAll(tag, class_)
|
all_tags = parent.find_all(tag, class_)
|
||||||
else:
|
else:
|
||||||
all_tags = parent.findAll(tag)
|
all_tags = parent.find_all(tag)
|
||||||
for element in all_tags:
|
for element in all_tags:
|
||||||
element.extract()
|
element.extract()
|
||||||
|
|
||||||
|
@ -93,14 +98,15 @@ class BGExtract(object):
|
||||||
"""
|
"""
|
||||||
if isinstance(tag, NavigableString):
|
if isinstance(tag, NavigableString):
|
||||||
return None, unicode(tag)
|
return None, unicode(tag)
|
||||||
elif tag.get('class') == 'versenum' or tag.get('class') == 'versenum mid-line':
|
elif tag.get('class')[0] == "versenum" or tag.get('class')[0] == 'versenum mid-line':
|
||||||
verse = unicode(tag.string).replace('[', '').replace(']', '').strip()
|
verse = unicode(tag.string).replace('[', '').replace(']', '').strip()
|
||||||
return verse, None
|
return verse, None
|
||||||
elif tag.get('class') == 'chapternum':
|
elif tag.get('class')[0] == 'chapternum':
|
||||||
verse = '1'
|
verse = '1'
|
||||||
return verse, None
|
return verse, None
|
||||||
else:
|
else:
|
||||||
verse, text = None, ''
|
verse = None
|
||||||
|
text = ''
|
||||||
for child in tag.contents:
|
for child in tag.contents:
|
||||||
c_verse, c_text = self._extract_verse(child)
|
c_verse, c_text = self._extract_verse(child)
|
||||||
if c_verse:
|
if c_verse:
|
||||||
|
@ -137,7 +143,8 @@ class BGExtract(object):
|
||||||
tags = tags[::-1]
|
tags = tags[::-1]
|
||||||
current_text = ''
|
current_text = ''
|
||||||
for tag in tags:
|
for tag in tags:
|
||||||
verse, text = None, ''
|
verse = None
|
||||||
|
text = ''
|
||||||
for child in tag.contents:
|
for child in tag.contents:
|
||||||
c_verse, c_text = self._extract_verse(child)
|
c_verse, c_text = self._extract_verse(child)
|
||||||
if c_verse:
|
if c_verse:
|
||||||
|
@ -173,8 +180,8 @@ class BGExtract(object):
|
||||||
|
|
||||||
def _extract_verses_old(self, div):
|
def _extract_verses_old(self, div):
|
||||||
"""
|
"""
|
||||||
Use the old style of parsing for those Bibles on BG who mysteriously
|
Use the old style of parsing for those Bibles on BG who mysteriously have not been migrated to the new (still
|
||||||
have not been migrated to the new (still broken) HTML.
|
broken) HTML.
|
||||||
|
|
||||||
``div``
|
``div``
|
||||||
The parent div.
|
The parent div.
|
||||||
|
@ -185,13 +192,12 @@ class BGExtract(object):
|
||||||
if first_verse and first_verse.contents:
|
if first_verse and first_verse.contents:
|
||||||
verse_list[1] = unicode(first_verse.contents[0])
|
verse_list[1] = unicode(first_verse.contents[0])
|
||||||
for verse in div(u'sup', u'versenum'):
|
for verse in div(u'sup', u'versenum'):
|
||||||
raw_verse_num = verse.next
|
raw_verse_num = verse.next_element
|
||||||
clean_verse_num = 0
|
clean_verse_num = 0
|
||||||
# Not all verses exist in all translations and may or may not be
|
# Not all verses exist in all translations and may or may not be represented by a verse number. If they are
|
||||||
# represented by a verse number. If they are not fine, if they are
|
# not fine, if they are it will probably be in a format that breaks int(). We will then have no idea what
|
||||||
# it will probably be in a format that breaks int(). We will then
|
# garbage may be sucked in to the verse text so if we do not get a clean int() then ignore the verse
|
||||||
# have no idea what garbage may be sucked in to the verse text so
|
# completely.
|
||||||
# if we do not get a clean int() then ignore the verse completely.
|
|
||||||
try:
|
try:
|
||||||
clean_verse_num = int(str(raw_verse_num))
|
clean_verse_num = int(str(raw_verse_num))
|
||||||
except ValueError:
|
except ValueError:
|
||||||
|
@ -201,16 +207,16 @@ class BGExtract(object):
|
||||||
except TypeError:
|
except TypeError:
|
||||||
log.warn(u'Illegal verse number: %s', unicode(raw_verse_num))
|
log.warn(u'Illegal verse number: %s', unicode(raw_verse_num))
|
||||||
if clean_verse_num:
|
if clean_verse_num:
|
||||||
verse_text = raw_verse_num.next
|
verse_text = raw_verse_num.next_element
|
||||||
part = raw_verse_num.next.next
|
part = raw_verse_num.next_element.next_element
|
||||||
while not (isinstance(part, Tag) and part.get(u'class') == u'versenum'):
|
while not (isinstance(part, Tag) and part.get(u'class')[0] == u'versenum'):
|
||||||
# While we are still in the same verse grab all the text.
|
# While we are still in the same verse grab all the text.
|
||||||
if isinstance(part, NavigableString):
|
if isinstance(part, NavigableString):
|
||||||
verse_text += part
|
verse_text += part
|
||||||
if isinstance(part.next, Tag) and part.next.name == u'div':
|
if isinstance(part.next_element, Tag) and part.next_element.name == u'div':
|
||||||
# Run out of verses so stop.
|
# Run out of verses so stop.
|
||||||
break
|
break
|
||||||
part = part.next
|
part = part.next_element
|
||||||
verse_list[clean_verse_num] = unicode(verse_text)
|
verse_list[clean_verse_num] = unicode(verse_text)
|
||||||
return verse_list
|
return verse_list
|
||||||
|
|
||||||
|
@ -230,15 +236,14 @@ class BGExtract(object):
|
||||||
log.debug(u'BGExtract.get_bible_chapter("%s", "%s", "%s")', version, book_name, chapter)
|
log.debug(u'BGExtract.get_bible_chapter("%s", "%s", "%s")', version, book_name, chapter)
|
||||||
url_book_name = urllib.quote(book_name.encode("utf-8"))
|
url_book_name = urllib.quote(book_name.encode("utf-8"))
|
||||||
url_params = u'search=%s+%s&version=%s' % (url_book_name, chapter, version)
|
url_params = u'search=%s+%s&version=%s' % (url_book_name, chapter, version)
|
||||||
cleaner = [(re.compile(' |<br />|\'\+\''), lambda match: '')]
|
|
||||||
soup = get_soup_for_bible_ref(
|
soup = get_soup_for_bible_ref(
|
||||||
u'http://www.biblegateway.com/passage/?%s' % url_params,
|
u'http://www.biblegateway.com/passage/?%s' % url_params,
|
||||||
pre_parse_regex=r'<meta name.*?/>', pre_parse_substitute='', cleaner=cleaner)
|
pre_parse_regex=r'<meta name.*?/>', pre_parse_substitute='')
|
||||||
if not soup:
|
if not soup:
|
||||||
return None
|
return None
|
||||||
div = soup.find('div', 'result-text-style-normal')
|
div = soup.find('div', 'result-text-style-normal')
|
||||||
self._clean_soup(div)
|
self._clean_soup(div)
|
||||||
span_list = div.findAll('span', 'text')
|
span_list = div.find_all('span', 'text')
|
||||||
log.debug('Span list: %s', span_list)
|
log.debug('Span list: %s', span_list)
|
||||||
if not span_list:
|
if not span_list:
|
||||||
# If we don't get any spans then we must have the old HTML format
|
# If we don't get any spans then we must have the old HTML format
|
||||||
|
@ -282,7 +287,7 @@ class BGExtract(object):
|
||||||
self.application.process_events()
|
self.application.process_events()
|
||||||
content = soup.find(u'table', u'infotable')
|
content = soup.find(u'table', u'infotable')
|
||||||
if content:
|
if content:
|
||||||
content = content.findAll(u'tr')
|
content = content.find_all(u'tr')
|
||||||
if not content:
|
if not content:
|
||||||
log.error(u'No books found in the Biblegateway response.')
|
log.error(u'No books found in the Biblegateway response.')
|
||||||
send_error_message(u'parse')
|
send_error_message(u'parse')
|
||||||
|
@ -341,19 +346,17 @@ class BSExtract(object):
|
||||||
log.error(u'No verses found in the Bibleserver response.')
|
log.error(u'No verses found in the Bibleserver response.')
|
||||||
send_error_message(u'parse')
|
send_error_message(u'parse')
|
||||||
return None
|
return None
|
||||||
content = content.find(u'div').findAll(u'div')
|
content = content.find(u'div').find_all(u'div')
|
||||||
verse_number = re.compile(r'v(\d{1,2})(\d{3})(\d{3}) verse.*')
|
|
||||||
verses = {}
|
verses = {}
|
||||||
for verse in content:
|
for verse in content:
|
||||||
self.application.process_events()
|
self.application.process_events()
|
||||||
versenumber = int(verse_number.sub(r'\3', verse[u'class']))
|
versenumber = int(VERSE_NUMBER_REGEX.sub(r'\3', u' '.join(verse[u'class'])))
|
||||||
verses[versenumber] = verse.contents[1].rstrip(u'\n')
|
verses[versenumber] = verse.contents[1].rstrip(u'\n')
|
||||||
return SearchResults(book_name, chapter, verses)
|
return SearchResults(book_name, chapter, verses)
|
||||||
|
|
||||||
def get_books_from_http(self, version):
|
def get_books_from_http(self, version):
|
||||||
"""
|
"""
|
||||||
Load a list of all books a Bible contains from Bibleserver mobile
|
Load a list of all books a Bible contains from Bibleserver mobile website.
|
||||||
website.
|
|
||||||
|
|
||||||
``version``
|
``version``
|
||||||
The version of the Bible like NIV for New International Version
|
The version of the Bible like NIV for New International Version
|
||||||
|
@ -369,9 +372,19 @@ class BSExtract(object):
|
||||||
log.error(u'No books found in the Bibleserver response.')
|
log.error(u'No books found in the Bibleserver response.')
|
||||||
send_error_message(u'parse')
|
send_error_message(u'parse')
|
||||||
return None
|
return None
|
||||||
content = content.findAll(u'li')
|
content = content.find_all(u'li')
|
||||||
return [book.contents[0].contents[0] for book in content]
|
return [book.contents[0].contents[0] for book in content]
|
||||||
|
|
||||||
|
def _get_application(self):
|
||||||
|
"""
|
||||||
|
Adds the openlp to the class dynamically
|
||||||
|
"""
|
||||||
|
if not hasattr(self, u'_application'):
|
||||||
|
self._application = Registry().get(u'application')
|
||||||
|
return self._application
|
||||||
|
|
||||||
|
application = property(_get_application)
|
||||||
|
|
||||||
|
|
||||||
class CWExtract(object):
|
class CWExtract(object):
|
||||||
"""
|
"""
|
||||||
|
@ -404,14 +417,12 @@ class CWExtract(object):
|
||||||
if not soup:
|
if not soup:
|
||||||
return None
|
return None
|
||||||
self.application.process_events()
|
self.application.process_events()
|
||||||
html_verses = soup.findAll(u'span', u'versetext')
|
html_verses = soup.find_all(u'span', u'versetext')
|
||||||
if not html_verses:
|
if not html_verses:
|
||||||
log.error(u'No verses found in the CrossWalk response.')
|
log.error(u'No verses found in the CrossWalk response.')
|
||||||
send_error_message(u'parse')
|
send_error_message(u'parse')
|
||||||
return None
|
return None
|
||||||
verses = {}
|
verses = {}
|
||||||
reduce_spaces = re.compile(r'[ ]{2,}')
|
|
||||||
fix_punctuation = re.compile(r'[ ]+([.,;])')
|
|
||||||
for verse in html_verses:
|
for verse in html_verses:
|
||||||
self.application.process_events()
|
self.application.process_events()
|
||||||
verse_number = int(verse.contents[0].contents[0])
|
verse_number = int(verse.contents[0].contents[0])
|
||||||
|
@ -432,11 +443,10 @@ class CWExtract(object):
|
||||||
if isinstance(subsub, NavigableString):
|
if isinstance(subsub, NavigableString):
|
||||||
verse_text += subsub
|
verse_text += subsub
|
||||||
self.application.process_events()
|
self.application.process_events()
|
||||||
# Fix up leading and trailing spaces, multiple spaces, and spaces
|
# Fix up leading and trailing spaces, multiple spaces, and spaces between text and , and .
|
||||||
# between text and , and .
|
|
||||||
verse_text = verse_text.strip(u'\n\r\t ')
|
verse_text = verse_text.strip(u'\n\r\t ')
|
||||||
verse_text = reduce_spaces.sub(u' ', verse_text)
|
verse_text = REDUCE_SPACES_REGEX.sub(u' ', verse_text)
|
||||||
verse_text = fix_punctuation.sub(r'\1', verse_text)
|
verse_text = FIX_PUNKCTUATION_REGEX.sub(r'\1', verse_text)
|
||||||
verses[verse_number] = verse_text
|
verses[verse_number] = verse_text
|
||||||
return SearchResults(book_name, chapter, verses)
|
return SearchResults(book_name, chapter, verses)
|
||||||
|
|
||||||
|
@ -458,7 +468,7 @@ class CWExtract(object):
|
||||||
log.error(u'No books found in the Crosswalk response.')
|
log.error(u'No books found in the Crosswalk response.')
|
||||||
send_error_message(u'parse')
|
send_error_message(u'parse')
|
||||||
return None
|
return None
|
||||||
content = content.findAll(u'li')
|
content = content.find_all(u'li')
|
||||||
books = []
|
books = []
|
||||||
for book in content:
|
for book in content:
|
||||||
book = book.find(u'a')
|
book = book.find(u'a')
|
||||||
|
@ -481,9 +491,8 @@ class HTTPBible(BibleDB):
|
||||||
|
|
||||||
def __init__(self, parent, **kwargs):
|
def __init__(self, parent, **kwargs):
|
||||||
"""
|
"""
|
||||||
Finds all the bibles defined for the system
|
Finds all the bibles defined for the system. Creates an Interface Object for each bible containing connection
|
||||||
Creates an Interface Object for each bible containing connection
|
information.
|
||||||
information
|
|
||||||
|
|
||||||
Throws Exception if no Bibles are found.
|
Throws Exception if no Bibles are found.
|
||||||
|
|
||||||
|
@ -492,8 +501,7 @@ class HTTPBible(BibleDB):
|
||||||
BibleDB.__init__(self, parent, **kwargs)
|
BibleDB.__init__(self, parent, **kwargs)
|
||||||
self.download_source = kwargs[u'download_source']
|
self.download_source = kwargs[u'download_source']
|
||||||
self.download_name = kwargs[u'download_name']
|
self.download_name = kwargs[u'download_name']
|
||||||
# TODO: Clean up proxy stuff. We probably want one global proxy per
|
# TODO: Clean up proxy stuff. We probably want one global proxy per connection type (HTTP and HTTPS) at most.
|
||||||
# connection type (HTTP and HTTPS) at most.
|
|
||||||
self.proxy_server = None
|
self.proxy_server = None
|
||||||
self.proxy_username = None
|
self.proxy_username = None
|
||||||
self.proxy_password = None
|
self.proxy_password = None
|
||||||
|
@ -508,8 +516,8 @@ class HTTPBible(BibleDB):
|
||||||
|
|
||||||
def do_import(self, bible_name=None):
|
def do_import(self, bible_name=None):
|
||||||
"""
|
"""
|
||||||
Run the import. This method overrides the parent class method. Returns
|
Run the import. This method overrides the parent class method. Returns ``True`` on success, ``False`` on
|
||||||
``True`` on success, ``False`` on failure.
|
failure.
|
||||||
"""
|
"""
|
||||||
self.wizard.progress_bar.setMaximum(68)
|
self.wizard.progress_bar.setMaximum(68)
|
||||||
self.wizard.increment_progress_bar(translate('BiblesPlugin.HTTPBible', 'Registering Bible and loading books...'))
|
self.wizard.increment_progress_bar(translate('BiblesPlugin.HTTPBible', 'Registering Bible and loading books...'))
|
||||||
|
@ -549,8 +557,7 @@ class HTTPBible(BibleDB):
|
||||||
if self.stop_import_flag:
|
if self.stop_import_flag:
|
||||||
break
|
break
|
||||||
self.wizard.increment_progress_bar(translate(
|
self.wizard.increment_progress_bar(translate(
|
||||||
'BiblesPlugin.HTTPBible', 'Importing %s...',
|
'BiblesPlugin.HTTPBible', 'Importing %s...', 'Importing <book name>...') % book)
|
||||||
'Importing <book name>...') % book)
|
|
||||||
book_ref_id = self.get_book_ref_id_by_name(book, len(books), language_id)
|
book_ref_id = self.get_book_ref_id_by_name(book, len(books), language_id)
|
||||||
if not book_ref_id:
|
if not book_ref_id:
|
||||||
log.exception(u'Importing books from %s - download name: "%s" '\
|
log.exception(u'Importing books from %s - download name: "%s" '\
|
||||||
|
@ -567,22 +574,19 @@ class HTTPBible(BibleDB):
|
||||||
|
|
||||||
def get_verses(self, reference_list, show_error=True):
|
def get_verses(self, reference_list, show_error=True):
|
||||||
"""
|
"""
|
||||||
A reimplementation of the ``BibleDB.get_verses`` method, this one is
|
A reimplementation of the ``BibleDB.get_verses`` method, this one is specifically for web Bibles. It first
|
||||||
specifically for web Bibles. It first checks to see if the particular
|
checks to see if the particular chapter exists in the DB, and if not it pulls it from the web. If the chapter
|
||||||
chapter exists in the DB, and if not it pulls it from the web. If the
|
DOES exist, it simply pulls the verses from the DB using the ancestor method.
|
||||||
chapter DOES exist, it simply pulls the verses from the DB using the
|
|
||||||
ancestor method.
|
|
||||||
|
|
||||||
``reference_list``
|
``reference_list``
|
||||||
This is the list of references the media manager item wants. It is
|
This is the list of references the media manager item wants. It is a list of tuples, with the following
|
||||||
a list of tuples, with the following format::
|
format::
|
||||||
|
|
||||||
(book_reference_id, chapter, start_verse, end_verse)
|
(book_reference_id, chapter, start_verse, end_verse)
|
||||||
|
|
||||||
Therefore, when you are looking for multiple items, simply break
|
Therefore, when you are looking for multiple items, simply break them up into references like this, bundle
|
||||||
them up into references like this, bundle them into a list. This
|
them into a list. This function then runs through the list, and returns an amalgamated list of ``Verse``
|
||||||
function then runs through the list, and returns an amalgamated
|
objects. For example::
|
||||||
list of ``Verse`` objects. For example::
|
|
||||||
|
|
||||||
[(u'35', 1, 1, 1), (u'35', 2, 2, 3)]
|
[(u'35', 1, 1, 1), (u'35', 2, 2, 3)]
|
||||||
"""
|
"""
|
||||||
|
@ -643,7 +647,7 @@ class HTTPBible(BibleDB):
|
||||||
Return the number of chapters in a particular book.
|
Return the number of chapters in a particular book.
|
||||||
|
|
||||||
``book``
|
``book``
|
||||||
The book object to get the chapter count for.
|
The book object to get the chapter count for.
|
||||||
"""
|
"""
|
||||||
log.debug(u'HTTPBible.get_chapter_count("%s")', book.name)
|
log.debug(u'HTTPBible.get_chapter_count("%s")', book.name)
|
||||||
return BiblesResourcesDB.get_chapter_count(book.book_reference_id)
|
return BiblesResourcesDB.get_chapter_count(book.book_reference_id)
|
||||||
|
@ -671,8 +675,7 @@ class HTTPBible(BibleDB):
|
||||||
|
|
||||||
application = property(_get_application)
|
application = property(_get_application)
|
||||||
|
|
||||||
def get_soup_for_bible_ref(reference_url, header=None, pre_parse_regex=None,
|
def get_soup_for_bible_ref(reference_url, header=None, pre_parse_regex=None, pre_parse_substitute=None):
|
||||||
pre_parse_substitute=None, cleaner=None):
|
|
||||||
"""
|
"""
|
||||||
Gets a webpage and returns a parsed and optionally cleaned soup or None.
|
Gets a webpage and returns a parsed and optionally cleaned soup or None.
|
||||||
|
|
||||||
|
@ -683,14 +686,11 @@ def get_soup_for_bible_ref(reference_url, header=None, pre_parse_regex=None,
|
||||||
An optional HTTP header to pass to the bible web server.
|
An optional HTTP header to pass to the bible web server.
|
||||||
|
|
||||||
``pre_parse_regex``
|
``pre_parse_regex``
|
||||||
A regular expression to run on the webpage. Allows manipulation of the
|
A regular expression to run on the webpage. Allows manipulation of the webpage before passing to BeautifulSoup
|
||||||
webpage before passing to BeautifulSoup for parsing.
|
for parsing.
|
||||||
|
|
||||||
``pre_parse_substitute``
|
``pre_parse_substitute``
|
||||||
The text to replace any matches to the regular expression with.
|
The text to replace any matches to the regular expression with.
|
||||||
|
|
||||||
``cleaner``
|
|
||||||
An optional regex to use during webpage parsing.
|
|
||||||
"""
|
"""
|
||||||
if not reference_url:
|
if not reference_url:
|
||||||
return None
|
return None
|
||||||
|
@ -703,10 +703,8 @@ def get_soup_for_bible_ref(reference_url, header=None, pre_parse_regex=None,
|
||||||
page_source = re.sub(pre_parse_regex, pre_parse_substitute, page_source)
|
page_source = re.sub(pre_parse_regex, pre_parse_substitute, page_source)
|
||||||
soup = None
|
soup = None
|
||||||
try:
|
try:
|
||||||
if cleaner:
|
soup = BeautifulSoup(page_source)
|
||||||
soup = BeautifulSoup(page_source, markupMassage=cleaner)
|
CLEANER_REGEX.sub(u'', unicode(soup))
|
||||||
else:
|
|
||||||
soup = BeautifulSoup(page_source)
|
|
||||||
except HTMLParseError:
|
except HTMLParseError:
|
||||||
log.exception(u'BeautifulSoup could not parse the bible page.')
|
log.exception(u'BeautifulSoup could not parse the bible page.')
|
||||||
if not soup:
|
if not soup:
|
||||||
|
@ -715,6 +713,7 @@ def get_soup_for_bible_ref(reference_url, header=None, pre_parse_regex=None,
|
||||||
Registry().get(u'application').process_events()
|
Registry().get(u'application').process_events()
|
||||||
return soup
|
return soup
|
||||||
|
|
||||||
|
|
||||||
def send_error_message(error_type):
|
def send_error_message(error_type):
|
||||||
"""
|
"""
|
||||||
Send a standard error message informing the user of an issue.
|
Send a standard error message informing the user of an issue.
|
||||||
|
|
|
@ -38,28 +38,21 @@ from csvbible import CSVBible
|
||||||
from http import HTTPBible
|
from http import HTTPBible
|
||||||
from opensong import OpenSongBible
|
from opensong import OpenSongBible
|
||||||
from osis import OSISBible
|
from osis import OSISBible
|
||||||
# Imports that might fail.
|
|
||||||
try:
|
|
||||||
from openlp1 import OpenLP1Bible
|
|
||||||
HAS_OPENLP1 = True
|
|
||||||
except ImportError:
|
|
||||||
HAS_OPENLP1 = False
|
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class BibleFormat(object):
|
class BibleFormat(object):
|
||||||
"""
|
"""
|
||||||
This is a special enumeration class that holds the various types of Bibles,
|
This is a special enumeration class that holds the various types of Bibles.
|
||||||
plus a few helper functions to facilitate generic handling of Bible types
|
|
||||||
for importing.
|
|
||||||
"""
|
"""
|
||||||
_format_availability = {}
|
|
||||||
Unknown = -1
|
Unknown = -1
|
||||||
OSIS = 0
|
OSIS = 0
|
||||||
CSV = 1
|
CSV = 1
|
||||||
OpenSong = 2
|
OpenSong = 2
|
||||||
WebDownload = 3
|
WebDownload = 3
|
||||||
OpenLP1 = 4
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_class(format):
|
def get_class(format):
|
||||||
|
@ -77,8 +70,6 @@ class BibleFormat(object):
|
||||||
return OpenSongBible
|
return OpenSongBible
|
||||||
elif format == BibleFormat.WebDownload:
|
elif format == BibleFormat.WebDownload:
|
||||||
return HTTPBible
|
return HTTPBible
|
||||||
elif format == BibleFormat.OpenLP1:
|
|
||||||
return OpenLP1Bible
|
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@ -92,17 +83,8 @@ class BibleFormat(object):
|
||||||
BibleFormat.CSV,
|
BibleFormat.CSV,
|
||||||
BibleFormat.OpenSong,
|
BibleFormat.OpenSong,
|
||||||
BibleFormat.WebDownload,
|
BibleFormat.WebDownload,
|
||||||
BibleFormat.OpenLP1
|
|
||||||
]
|
]
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def set_availability(format, available):
|
|
||||||
BibleFormat._format_availability[format] = available
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def get_availability(format):
|
|
||||||
return BibleFormat._format_availability.get(format, True)
|
|
||||||
|
|
||||||
|
|
||||||
class BibleManager(object):
|
class BibleManager(object):
|
||||||
"""
|
"""
|
||||||
|
@ -463,6 +445,5 @@ class BibleManager(object):
|
||||||
|
|
||||||
main_window = property(_get_main_window)
|
main_window = property(_get_main_window)
|
||||||
|
|
||||||
BibleFormat.set_availability(BibleFormat.OpenLP1, HAS_OPENLP1)
|
|
||||||
|
|
||||||
__all__ = [u'BibleFormat']
|
__all__ = [u'BibleFormat']
|
||||||
|
|
|
@ -61,8 +61,8 @@ class BibleMediaItem(MediaManagerItem):
|
||||||
|
|
||||||
def __init__(self, parent, plugin):
|
def __init__(self, parent, plugin):
|
||||||
self.icon_path = u'songs/song'
|
self.icon_path = u'songs/song'
|
||||||
self.lockIcon = build_icon(u':/bibles/bibles_search_lock.png')
|
self.lock_icon = build_icon(u':/bibles/bibles_search_lock.png')
|
||||||
self.unlockIcon = build_icon(u':/bibles/bibles_search_unlock.png')
|
self.unlock_icon = build_icon(u':/bibles/bibles_search_unlock.png')
|
||||||
MediaManagerItem.__init__(self, parent, plugin)
|
MediaManagerItem.__init__(self, parent, plugin)
|
||||||
# Place to store the search results for both bibles.
|
# Place to store the search results for both bibles.
|
||||||
self.settings = self.plugin.settings_tab
|
self.settings = self.plugin.settings_tab
|
||||||
|
@ -73,7 +73,7 @@ class BibleMediaItem(MediaManagerItem):
|
||||||
self.check_search_result()
|
self.check_search_result()
|
||||||
Registry().register_function(u'bibles_load_list', self.reload_bibles)
|
Registry().register_function(u'bibles_load_list', self.reload_bibles)
|
||||||
|
|
||||||
def __checkSecondBible(self, bible, second_bible):
|
def __check_second_bible(self, bible, second_bible):
|
||||||
"""
|
"""
|
||||||
Check if the first item is a second bible item or not.
|
Check if the first item is a second bible item or not.
|
||||||
"""
|
"""
|
||||||
|
@ -84,7 +84,7 @@ class BibleMediaItem(MediaManagerItem):
|
||||||
self.displayResults(bible, second_bible)
|
self.displayResults(bible, second_bible)
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
item_second_bible = self._decodeQtObject(bitem, 'second_bible')
|
item_second_bible = self._decode_qt_object(bitem, 'second_bible')
|
||||||
if item_second_bible and second_bible or not item_second_bible and not second_bible:
|
if item_second_bible and second_bible or not item_second_bible and not second_bible:
|
||||||
self.displayResults(bible, second_bible)
|
self.displayResults(bible, second_bible)
|
||||||
elif critical_error_message_box(
|
elif critical_error_message_box(
|
||||||
|
@ -95,7 +95,7 @@ class BibleMediaItem(MediaManagerItem):
|
||||||
self.list_view.clear()
|
self.list_view.clear()
|
||||||
self.displayResults(bible, second_bible)
|
self.displayResults(bible, second_bible)
|
||||||
|
|
||||||
def _decodeQtObject(self, bitem, key):
|
def _decode_qt_object(self, bitem, key):
|
||||||
reference = bitem.data(QtCore.Qt.UserRole)
|
reference = bitem.data(QtCore.Qt.UserRole)
|
||||||
obj = reference[unicode(key)]
|
obj = reference[unicode(key)]
|
||||||
return unicode(obj).strip()
|
return unicode(obj).strip()
|
||||||
|
@ -159,7 +159,7 @@ class BibleMediaItem(MediaManagerItem):
|
||||||
search_button_layout.setObjectName(prefix + u'search_button_layout')
|
search_button_layout.setObjectName(prefix + u'search_button_layout')
|
||||||
search_button_layout.addStretch()
|
search_button_layout.addStretch()
|
||||||
lockButton = QtGui.QToolButton(tab)
|
lockButton = QtGui.QToolButton(tab)
|
||||||
lockButton.setIcon(self.unlockIcon)
|
lockButton.setIcon(self.unlock_icon)
|
||||||
lockButton.setCheckable(True)
|
lockButton.setCheckable(True)
|
||||||
lockButton.setObjectName(prefix + u'LockButton')
|
lockButton.setObjectName(prefix + u'LockButton')
|
||||||
search_button_layout.addWidget(lockButton)
|
search_button_layout.addWidget(lockButton)
|
||||||
|
@ -250,7 +250,7 @@ class BibleMediaItem(MediaManagerItem):
|
||||||
self.quickSearchEdit.returnPressed.connect(self.onQuickSearchButton)
|
self.quickSearchEdit.returnPressed.connect(self.onQuickSearchButton)
|
||||||
self.searchTabBar.currentChanged.connect(self.onSearchTabBarCurrentChanged)
|
self.searchTabBar.currentChanged.connect(self.onSearchTabBarCurrentChanged)
|
||||||
|
|
||||||
def onFocus(self):
|
def on_focus(self):
|
||||||
if self.quickTab.isVisible():
|
if self.quickTab.isVisible():
|
||||||
self.quickSearchEdit.setFocus()
|
self.quickSearchEdit.setFocus()
|
||||||
else:
|
else:
|
||||||
|
@ -509,9 +509,9 @@ class BibleMediaItem(MediaManagerItem):
|
||||||
|
|
||||||
def onLockButtonToggled(self, checked):
|
def onLockButtonToggled(self, checked):
|
||||||
if checked:
|
if checked:
|
||||||
self.sender().setIcon(self.lockIcon)
|
self.sender().setIcon(self.lock_icon)
|
||||||
else:
|
else:
|
||||||
self.sender().setIcon(self.unlockIcon)
|
self.sender().setIcon(self.unlock_icon)
|
||||||
|
|
||||||
def onQuickStyleComboBoxChanged(self):
|
def onQuickStyleComboBoxChanged(self):
|
||||||
self.settings.layout_style = self.quickStyleComboBox.currentIndex()
|
self.settings.layout_style = self.quickStyleComboBox.currentIndex()
|
||||||
|
@ -633,7 +633,7 @@ class BibleMediaItem(MediaManagerItem):
|
||||||
if not self.advancedLockButton.isChecked():
|
if not self.advancedLockButton.isChecked():
|
||||||
self.list_view.clear()
|
self.list_view.clear()
|
||||||
if self.list_view.count() != 0:
|
if self.list_view.count() != 0:
|
||||||
self.__checkSecondBible(bible, second_bible)
|
self.__check_second_bible(bible, second_bible)
|
||||||
elif self.search_results:
|
elif self.search_results:
|
||||||
self.displayResults(bible, second_bible)
|
self.displayResults(bible, second_bible)
|
||||||
self.advancedSearchButton.setEnabled(True)
|
self.advancedSearchButton.setEnabled(True)
|
||||||
|
@ -689,7 +689,7 @@ class BibleMediaItem(MediaManagerItem):
|
||||||
if not self.quickLockButton.isChecked():
|
if not self.quickLockButton.isChecked():
|
||||||
self.list_view.clear()
|
self.list_view.clear()
|
||||||
if self.list_view.count() != 0 and self.search_results:
|
if self.list_view.count() != 0 and self.search_results:
|
||||||
self.__checkSecondBible(bible, second_bible)
|
self.__check_second_bible(bible, second_bible)
|
||||||
elif self.search_results:
|
elif self.search_results:
|
||||||
self.displayResults(bible, second_bible)
|
self.displayResults(bible, second_bible)
|
||||||
self.quickSearchButton.setEnabled(True)
|
self.quickSearchButton.setEnabled(True)
|
||||||
|
@ -787,19 +787,19 @@ class BibleMediaItem(MediaManagerItem):
|
||||||
raw_title = []
|
raw_title = []
|
||||||
verses = VerseReferenceList()
|
verses = VerseReferenceList()
|
||||||
for bitem in items:
|
for bitem in items:
|
||||||
book = self._decodeQtObject(bitem, 'book')
|
book = self._decode_qt_object(bitem, 'book')
|
||||||
chapter = int(self._decodeQtObject(bitem, 'chapter'))
|
chapter = int(self._decode_qt_object(bitem, 'chapter'))
|
||||||
verse = int(self._decodeQtObject(bitem, 'verse'))
|
verse = int(self._decode_qt_object(bitem, 'verse'))
|
||||||
bible = self._decodeQtObject(bitem, 'bible')
|
bible = self._decode_qt_object(bitem, 'bible')
|
||||||
version = self._decodeQtObject(bitem, 'version')
|
version = self._decode_qt_object(bitem, 'version')
|
||||||
copyright = self._decodeQtObject(bitem, 'copyright')
|
copyright = self._decode_qt_object(bitem, 'copyright')
|
||||||
permissions = self._decodeQtObject(bitem, 'permissions')
|
permissions = self._decode_qt_object(bitem, 'permissions')
|
||||||
text = self._decodeQtObject(bitem, 'text')
|
text = self._decode_qt_object(bitem, 'text')
|
||||||
second_bible = self._decodeQtObject(bitem, 'second_bible')
|
second_bible = self._decode_qt_object(bitem, 'second_bible')
|
||||||
second_version = self._decodeQtObject(bitem, 'second_version')
|
second_version = self._decode_qt_object(bitem, 'second_version')
|
||||||
second_copyright = self._decodeQtObject(bitem, 'second_copyright')
|
second_copyright = self._decode_qt_object(bitem, 'second_copyright')
|
||||||
second_permissions = self._decodeQtObject(bitem, 'second_permissions')
|
second_permissions = self._decode_qt_object(bitem, 'second_permissions')
|
||||||
second_text = self._decodeQtObject(bitem, 'second_text')
|
second_text = self._decode_qt_object(bitem, 'second_text')
|
||||||
verses.add(book, chapter, verse, version, copyright, permissions)
|
verses.add(book, chapter, verse, version, copyright, permissions)
|
||||||
verse_text = self.formatVerse(old_chapter, chapter, verse)
|
verse_text = self.formatVerse(old_chapter, chapter, verse)
|
||||||
if second_bible:
|
if second_bible:
|
||||||
|
@ -867,13 +867,13 @@ class BibleMediaItem(MediaManagerItem):
|
||||||
"""
|
"""
|
||||||
verse_separator = get_reference_separator(u'sep_v_display')
|
verse_separator = get_reference_separator(u'sep_v_display')
|
||||||
range_separator = get_reference_separator(u'sep_r_display')
|
range_separator = get_reference_separator(u'sep_r_display')
|
||||||
old_chapter = self._decodeQtObject(old_bitem, 'chapter')
|
old_chapter = self._decode_qt_object(old_bitem, 'chapter')
|
||||||
old_verse = self._decodeQtObject(old_bitem, 'verse')
|
old_verse = self._decode_qt_object(old_bitem, 'verse')
|
||||||
start_book = self._decodeQtObject(start_bitem, 'book')
|
start_book = self._decode_qt_object(start_bitem, 'book')
|
||||||
start_chapter = self._decodeQtObject(start_bitem, 'chapter')
|
start_chapter = self._decode_qt_object(start_bitem, 'chapter')
|
||||||
start_verse = self._decodeQtObject(start_bitem, 'verse')
|
start_verse = self._decode_qt_object(start_bitem, 'verse')
|
||||||
start_bible = self._decodeQtObject(start_bitem, 'bible')
|
start_bible = self._decode_qt_object(start_bitem, 'bible')
|
||||||
start_second_bible = self._decodeQtObject(start_bitem, 'second_bible')
|
start_second_bible = self._decode_qt_object(start_bitem, 'second_bible')
|
||||||
if start_second_bible:
|
if start_second_bible:
|
||||||
bibles = u'%s, %s' % (start_bible, start_second_bible)
|
bibles = u'%s, %s' % (start_bible, start_second_bible)
|
||||||
else:
|
else:
|
||||||
|
@ -901,16 +901,16 @@ class BibleMediaItem(MediaManagerItem):
|
||||||
The item we were previously dealing with.
|
The item we were previously dealing with.
|
||||||
"""
|
"""
|
||||||
# Get all the necessary meta data.
|
# Get all the necessary meta data.
|
||||||
book = self._decodeQtObject(bitem, 'book')
|
book = self._decode_qt_object(bitem, 'book')
|
||||||
chapter = int(self._decodeQtObject(bitem, 'chapter'))
|
chapter = int(self._decode_qt_object(bitem, 'chapter'))
|
||||||
verse = int(self._decodeQtObject(bitem, 'verse'))
|
verse = int(self._decode_qt_object(bitem, 'verse'))
|
||||||
bible = self._decodeQtObject(bitem, 'bible')
|
bible = self._decode_qt_object(bitem, 'bible')
|
||||||
second_bible = self._decodeQtObject(bitem, 'second_bible')
|
second_bible = self._decode_qt_object(bitem, 'second_bible')
|
||||||
old_book = self._decodeQtObject(old_bitem, 'book')
|
old_book = self._decode_qt_object(old_bitem, 'book')
|
||||||
old_chapter = int(self._decodeQtObject(old_bitem, 'chapter'))
|
old_chapter = int(self._decode_qt_object(old_bitem, 'chapter'))
|
||||||
old_verse = int(self._decodeQtObject(old_bitem, 'verse'))
|
old_verse = int(self._decode_qt_object(old_bitem, 'verse'))
|
||||||
old_bible = self._decodeQtObject(old_bitem, 'bible')
|
old_bible = self._decode_qt_object(old_bitem, 'bible')
|
||||||
old_second_bible = self._decodeQtObject(old_bitem, 'second_bible')
|
old_second_bible = self._decode_qt_object(old_bitem, 'second_bible')
|
||||||
if old_bible != bible or old_second_bible != second_bible or old_book != book:
|
if old_bible != bible or old_second_bible != second_bible or old_book != book:
|
||||||
# The bible, second bible or book has changed.
|
# The bible, second bible or book has changed.
|
||||||
return True
|
return True
|
||||||
|
|
|
@ -1,113 +0,0 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
# OpenLP - Open Source Lyrics Projection #
|
|
||||||
# --------------------------------------------------------------------------- #
|
|
||||||
# Copyright (c) 2008-2013 Raoul Snyman #
|
|
||||||
# Portions copyright (c) 2008-2013 Tim Bentley, Gerald Britton, Jonathan #
|
|
||||||
# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, #
|
|
||||||
# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. #
|
|
||||||
# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, #
|
|
||||||
# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, #
|
|
||||||
# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, #
|
|
||||||
# Frode Woldsund, Martin Zibricky, Patrick Zimmermann #
|
|
||||||
# --------------------------------------------------------------------------- #
|
|
||||||
# This program is free software; you can redistribute it and/or modify it #
|
|
||||||
# under the terms of the GNU General Public License as published by the Free #
|
|
||||||
# Software Foundation; version 2 of the License. #
|
|
||||||
# #
|
|
||||||
# This program is distributed in the hope that it will be useful, but WITHOUT #
|
|
||||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
|
|
||||||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
|
|
||||||
# more details. #
|
|
||||||
# #
|
|
||||||
# You should have received a copy of the GNU General Public License along #
|
|
||||||
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
|
|
||||||
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
|
||||||
###############################################################################
|
|
||||||
|
|
||||||
import logging
|
|
||||||
import sqlite
|
|
||||||
import sys
|
|
||||||
|
|
||||||
from openlp.core.ui.wizard import WizardStrings
|
|
||||||
from openlp.plugins.bibles.lib.db import BibleDB, BiblesResourcesDB
|
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
class OpenLP1Bible(BibleDB):
|
|
||||||
"""
|
|
||||||
This class provides the OpenLPv1 bible importer.
|
|
||||||
"""
|
|
||||||
def __init__(self, parent, **kwargs):
|
|
||||||
"""
|
|
||||||
Constructor.
|
|
||||||
"""
|
|
||||||
log.debug(self.__class__.__name__)
|
|
||||||
BibleDB.__init__(self, parent, **kwargs)
|
|
||||||
self.filename = kwargs[u'filename']
|
|
||||||
|
|
||||||
def do_import(self, bible_name=None):
|
|
||||||
"""
|
|
||||||
Imports an openlp.org v1 bible.
|
|
||||||
"""
|
|
||||||
connection = None
|
|
||||||
cursor = None
|
|
||||||
try:
|
|
||||||
connection = sqlite.connect(self.filename.encode(sys.getfilesystemencoding()))
|
|
||||||
cursor = connection.cursor()
|
|
||||||
except sqlite.DatabaseError:
|
|
||||||
log.exception(u'File "%s" is encrypted or not a sqlite database, '
|
|
||||||
'therefore not an openlp.org 1.x database either' % self.filename)
|
|
||||||
# Please add an user error here!
|
|
||||||
# This file is not an openlp.org 1.x bible database.
|
|
||||||
return False
|
|
||||||
#Create the bible language
|
|
||||||
language_id = self.get_language(bible_name)
|
|
||||||
if not language_id:
|
|
||||||
log.exception(u'Importing books from "%s" failed' % self.filename)
|
|
||||||
return False
|
|
||||||
# Create all books.
|
|
||||||
try:
|
|
||||||
cursor.execute(u'SELECT id, testament_id, name, abbreviation FROM book')
|
|
||||||
except sqlite.DatabaseError as error:
|
|
||||||
log.exception(u'DatabaseError: %s' % error)
|
|
||||||
# Please add an user error here!
|
|
||||||
# This file is not an openlp.org 1.x bible database.
|
|
||||||
return False
|
|
||||||
books = cursor.fetchall()
|
|
||||||
self.wizard.progress_bar.setMaximum(len(books) + 1)
|
|
||||||
for book in books:
|
|
||||||
if self.stop_import_flag:
|
|
||||||
connection.close()
|
|
||||||
return False
|
|
||||||
book_id = int(book[0])
|
|
||||||
testament_id = int(book[1])
|
|
||||||
name = unicode(book[2], u'cp1252')
|
|
||||||
abbreviation = unicode(book[3], u'cp1252')
|
|
||||||
book_ref_id = self.get_book_ref_id_by_name(name, len(books),
|
|
||||||
language_id)
|
|
||||||
if not book_ref_id:
|
|
||||||
log.exception(u'Importing books from "%s" failed' % self.filename)
|
|
||||||
return False
|
|
||||||
book_details = BiblesResourcesDB.get_book_by_id(book_ref_id)
|
|
||||||
db_book = self.create_book(name, book_ref_id, book_details[u'testament_id'])
|
|
||||||
# Update the progess bar.
|
|
||||||
self.wizard.increment_progress_bar(WizardStrings.ImportingType % name)
|
|
||||||
# Import the verses for this book.
|
|
||||||
cursor.execute(u'SELECT chapter, verse, text || \'\' AS text FROM '
|
|
||||||
'verse WHERE book_id=%s' % book_id)
|
|
||||||
verses = cursor.fetchall()
|
|
||||||
for verse in verses:
|
|
||||||
if self.stop_import_flag:
|
|
||||||
connection.close()
|
|
||||||
return False
|
|
||||||
chapter = int(verse[0])
|
|
||||||
verse_number = int(verse[1])
|
|
||||||
text = unicode(verse[2], u'cp1252')
|
|
||||||
self.create_verse(db_book.id, chapter, verse_number, text)
|
|
||||||
self.application.process_events()
|
|
||||||
self.session.commit()
|
|
||||||
connection.close()
|
|
||||||
return True
|
|
|
@ -34,16 +34,18 @@ from openlp.core.lib import translate
|
||||||
from openlp.core.lib.ui import critical_error_message_box
|
from openlp.core.lib.ui import critical_error_message_box
|
||||||
from openlp.plugins.bibles.lib.db import BibleDB, BiblesResourcesDB
|
from openlp.plugins.bibles.lib.db import BibleDB, BiblesResourcesDB
|
||||||
|
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class OpenSongBible(BibleDB):
|
class OpenSongBible(BibleDB):
|
||||||
"""
|
"""
|
||||||
OpenSong Bible format importer class.
|
OpenSong Bible format importer class.
|
||||||
"""
|
"""
|
||||||
def __init__(self, parent, **kwargs):
|
def __init__(self, parent, **kwargs):
|
||||||
"""
|
"""
|
||||||
Constructor to create and set up an instance of the OpenSongBible
|
Constructor to create and set up an instance of the OpenSongBible class. This class is used to import Bibles
|
||||||
class. This class is used to import Bibles from OpenSong's XML format.
|
from OpenSong's XML format.
|
||||||
"""
|
"""
|
||||||
log.debug(self.__class__.__name__)
|
log.debug(self.__class__.__name__)
|
||||||
BibleDB.__init__(self, parent, **kwargs)
|
BibleDB.__init__(self, parent, **kwargs)
|
||||||
|
@ -75,9 +77,8 @@ class OpenSongBible(BibleDB):
|
||||||
file = None
|
file = None
|
||||||
success = True
|
success = True
|
||||||
try:
|
try:
|
||||||
# NOTE: We don't need to do any of the normal encoding detection
|
# NOTE: We don't need to do any of the normal encoding detection here, because lxml does it's own encoding
|
||||||
# here, because lxml does it's own encoding detection, and the two
|
# detection, and the two mechanisms together interfere with each other.
|
||||||
# mechanisms together interfere with each other.
|
|
||||||
file = open(self.filename, u'r')
|
file = open(self.filename, u'r')
|
||||||
opensong = objectify.parse(file)
|
opensong = objectify.parse(file)
|
||||||
bible = opensong.getroot()
|
bible = opensong.getroot()
|
||||||
|
@ -116,16 +117,11 @@ class OpenSongBible(BibleDB):
|
||||||
if len(verse_parts) > 1:
|
if len(verse_parts) > 1:
|
||||||
number = int(verse_parts[0])
|
number = int(verse_parts[0])
|
||||||
except TypeError:
|
except TypeError:
|
||||||
log.warn(u'Illegal verse number: %s',
|
log.warn(u'Illegal verse number: %s', unicode(verse.attrib[u'n']))
|
||||||
unicode(verse.attrib[u'n']))
|
|
||||||
verse_number = number
|
verse_number = number
|
||||||
else:
|
else:
|
||||||
verse_number += 1
|
verse_number += 1
|
||||||
self.create_verse(
|
self.create_verse(db_book.id, chapter_number, verse_number, self.get_text(verse))
|
||||||
db_book.id,
|
|
||||||
chapter_number,
|
|
||||||
verse_number,
|
|
||||||
self.get_text(verse))
|
|
||||||
self.wizard.increment_progress_bar(translate('BiblesPlugin.Opensong', 'Importing %s %s...',
|
self.wizard.increment_progress_bar(translate('BiblesPlugin.Opensong', 'Importing %s %s...',
|
||||||
'Importing <book name> <chapter>...')) % (db_book.name, chapter_number)
|
'Importing <book name> <chapter>...')) % (db_book.name, chapter_number)
|
||||||
self.session.commit()
|
self.session.commit()
|
||||||
|
|
|
@ -39,9 +39,11 @@ from openlp.plugins.bibles.lib.db import BibleDB, BiblesResourcesDB
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def replacement(match):
|
def replacement(match):
|
||||||
return match.group(2).upper()
|
return match.group(2).upper()
|
||||||
|
|
||||||
|
|
||||||
class OSISBible(BibleDB):
|
class OSISBible(BibleDB):
|
||||||
"""
|
"""
|
||||||
`OSIS <http://www.bibletechnologies.net/>`_ Bible format importer class.
|
`OSIS <http://www.bibletechnologies.net/>`_ Bible format importer class.
|
||||||
|
@ -53,8 +55,7 @@ class OSISBible(BibleDB):
|
||||||
BibleDB.__init__(self, parent, **kwargs)
|
BibleDB.__init__(self, parent, **kwargs)
|
||||||
self.filename = kwargs[u'filename']
|
self.filename = kwargs[u'filename']
|
||||||
self.language_regex = re.compile(r'<language.*>(.*?)</language>')
|
self.language_regex = re.compile(r'<language.*>(.*?)</language>')
|
||||||
self.verse_regex = re.compile(
|
self.verse_regex = re.compile(r'<verse osisID="([a-zA-Z0-9 ]*).([0-9]*).([0-9]*)">(.*?)</verse>')
|
||||||
r'<verse osisID="([a-zA-Z0-9 ]*).([0-9]*).([0-9]*)">(.*?)</verse>')
|
|
||||||
self.note_regex = re.compile(r'<note(.*?)>(.*?)</note>')
|
self.note_regex = re.compile(r'<note(.*?)>(.*?)</note>')
|
||||||
self.title_regex = re.compile(r'<title(.*?)>(.*?)</title>')
|
self.title_regex = re.compile(r'<title(.*?)>(.*?)</title>')
|
||||||
self.milestone_regex = re.compile(r'<milestone(.*?)/>')
|
self.milestone_regex = re.compile(r'<milestone(.*?)/>')
|
||||||
|
@ -68,8 +69,7 @@ class OSISBible(BibleDB):
|
||||||
self.q1_regex = re.compile(r'<q(.*?)level="1"(.*?)>')
|
self.q1_regex = re.compile(r'<q(.*?)level="1"(.*?)>')
|
||||||
self.q2_regex = re.compile(r'<q(.*?)level="2"(.*?)>')
|
self.q2_regex = re.compile(r'<q(.*?)level="2"(.*?)>')
|
||||||
self.trans_regex = re.compile(r'<transChange(.*?)>(.*?)</transChange>')
|
self.trans_regex = re.compile(r'<transChange(.*?)>(.*?)</transChange>')
|
||||||
self.divine_name_regex = re.compile(
|
self.divine_name_regex = re.compile(r'<divineName(.*?)>(.*?)</divineName>')
|
||||||
r'<divineName(.*?)>(.*?)</divineName>')
|
|
||||||
self.spaces_regex = re.compile(r'([ ]{2,})')
|
self.spaces_regex = re.compile(r'([ ]{2,})')
|
||||||
filepath = os.path.join(
|
filepath = os.path.join(
|
||||||
AppLocation.get_directory(AppLocation.PluginsDir), u'bibles', u'resources', u'osisbooks.csv')
|
AppLocation.get_directory(AppLocation.PluginsDir), u'bibles', u'resources', u'osisbooks.csv')
|
||||||
|
@ -158,10 +158,8 @@ class OSISBible(BibleDB):
|
||||||
self.wizard.increment_progress_bar(translate('BiblesPlugin.OsisImport', 'Importing %s %s...',
|
self.wizard.increment_progress_bar(translate('BiblesPlugin.OsisImport', 'Importing %s %s...',
|
||||||
'Importing <book name> <chapter>...') % (book_details[u'name'], chapter))
|
'Importing <book name> <chapter>...') % (book_details[u'name'], chapter))
|
||||||
last_chapter = chapter
|
last_chapter = chapter
|
||||||
# All of this rigmarol below is because the mod2osis
|
# All of this rigmarol below is because the mod2osis tool from the Sword library embeds XML in the
|
||||||
# tool from the Sword library embeds XML in the OSIS
|
# OSIS but neglects to enclose the verse text (with XML) in <[CDATA[ ]]> tags.
|
||||||
# but neglects to enclose the verse text (with XML) in
|
|
||||||
# <[CDATA[ ]]> tags.
|
|
||||||
verse_text = self.note_regex.sub(u'', verse_text)
|
verse_text = self.note_regex.sub(u'', verse_text)
|
||||||
verse_text = self.title_regex.sub(u'', verse_text)
|
verse_text = self.title_regex.sub(u'', verse_text)
|
||||||
verse_text = self.milestone_regex.sub(u'', verse_text)
|
verse_text = self.milestone_regex.sub(u'', verse_text)
|
||||||
|
|
|
@ -27,8 +27,7 @@
|
||||||
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
||||||
###############################################################################
|
###############################################################################
|
||||||
"""
|
"""
|
||||||
The :mod:`upgrade` module provides a way for the database and schema that is the
|
The :mod:`upgrade` module provides a way for the database and schema that is the backend for the Bibles plugin.
|
||||||
backend for the Bibles plugin
|
|
||||||
"""
|
"""
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
|
|
@ -29,8 +29,8 @@
|
||||||
|
|
||||||
class VerseReferenceList(object):
|
class VerseReferenceList(object):
|
||||||
"""
|
"""
|
||||||
The VerseReferenceList class encapsulates a list of verse references, but
|
The VerseReferenceList class encapsulates a list of verse references, but maintains the order in which they were
|
||||||
maintains the order in which they were added.
|
added.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
|
|
@ -257,6 +257,6 @@ class EditCustomForm(QtGui.QDialog, Ui_CustomEditDialog):
|
||||||
# We must have at least one slide.
|
# We must have at least one slide.
|
||||||
if self.slide_list_view.count() == 0:
|
if self.slide_list_view.count() == 0:
|
||||||
critical_error_message_box(message=translate('CustomPlugin.EditCustomForm',
|
critical_error_message_box(message=translate('CustomPlugin.EditCustomForm',
|
||||||
'You need to add at least one slide'))
|
'You need to add at least one slide.'))
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
|
@ -40,6 +40,7 @@ from openlp.plugins.custom.lib.db import CustomSlide
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class CustomSearch(object):
|
class CustomSearch(object):
|
||||||
"""
|
"""
|
||||||
An enumeration for custom search methods.
|
An enumeration for custom search methods.
|
||||||
|
@ -63,14 +64,14 @@ class CustomMediaItem(MediaManagerItem):
|
||||||
self.has_search = True
|
self.has_search = True
|
||||||
# Holds information about whether the edit is remotely triggered and
|
# Holds information about whether the edit is remotely triggered and
|
||||||
# which Custom is required.
|
# which Custom is required.
|
||||||
self.remoteCustom = -1
|
self.remote_custom = -1
|
||||||
self.manager = plugin.manager
|
self.manager = plugin.manager
|
||||||
|
|
||||||
def add_end_header_bar(self):
|
def add_end_header_bar(self):
|
||||||
self.toolbar.addSeparator()
|
self.toolbar.addSeparator()
|
||||||
self.add_search_to_toolbar()
|
self.add_search_to_toolbar()
|
||||||
# Signals and slots
|
# Signals and slots
|
||||||
QtCore.QObject.connect(self.search_text_edit, QtCore.SIGNAL(u'cleared()'), self.onClearTextButtonClick)
|
QtCore.QObject.connect(self.search_text_edit, QtCore.SIGNAL(u'cleared()'), self.on_clear_text_button_click)
|
||||||
QtCore.QObject.connect(self.search_text_edit, QtCore.SIGNAL(u'searchTypeChanged(int)'),
|
QtCore.QObject.connect(self.search_text_edit, QtCore.SIGNAL(u'searchTypeChanged(int)'),
|
||||||
self.on_search_text_button_clicked)
|
self.on_search_text_button_clicked)
|
||||||
Registry().register_function(u'custom_load_list', self.load_list)
|
Registry().register_function(u'custom_load_list', self.load_list)
|
||||||
|
@ -119,14 +120,13 @@ class CustomMediaItem(MediaManagerItem):
|
||||||
def on_new_click(self):
|
def on_new_click(self):
|
||||||
self.edit_custom_form.load_custom(0)
|
self.edit_custom_form.load_custom(0)
|
||||||
self.edit_custom_form.exec_()
|
self.edit_custom_form.exec_()
|
||||||
self.onClearTextButtonClick()
|
self.on_clear_text_button_click()
|
||||||
self.on_selection_change()
|
self.on_selection_change()
|
||||||
|
|
||||||
def onRemoteEdit(self, custom_id, preview=False):
|
def on_remote_edit(self, custom_id, preview=False):
|
||||||
"""
|
"""
|
||||||
Called by ServiceManager or SlideController by event passing
|
Called by ServiceManager or SlideController by event passing the custom Id in the payload along with an
|
||||||
the custom Id in the payload along with an indicator to say which
|
indicator to say which type of display is required.
|
||||||
type of display is required.
|
|
||||||
"""
|
"""
|
||||||
custom_id = int(custom_id)
|
custom_id = int(custom_id)
|
||||||
valid = self.manager.get_object(CustomSlide, custom_id)
|
valid = self.manager.get_object(CustomSlide, custom_id)
|
||||||
|
@ -134,12 +134,12 @@ class CustomMediaItem(MediaManagerItem):
|
||||||
self.edit_custom_form.load_custom(custom_id, preview)
|
self.edit_custom_form.load_custom(custom_id, preview)
|
||||||
if self.edit_custom_form.exec_() == QtGui.QDialog.Accepted:
|
if self.edit_custom_form.exec_() == QtGui.QDialog.Accepted:
|
||||||
self.remote_triggered = True
|
self.remote_triggered = True
|
||||||
self.remoteCustom = custom_id
|
self.remote_custom = custom_id
|
||||||
self.auto_select_id = -1
|
self.auto_select_id = -1
|
||||||
self.on_search_text_button_clicked()
|
self.on_search_text_button_clicked()
|
||||||
item = self.build_service_item(remote=True)
|
item = self.build_service_item(remote=True)
|
||||||
self.remote_triggered = None
|
self.remote_triggered = None
|
||||||
self.remoteCustom = 1
|
self.remote_custom = 1
|
||||||
if item:
|
if item:
|
||||||
return item
|
return item
|
||||||
return None
|
return None
|
||||||
|
@ -163,22 +163,21 @@ class CustomMediaItem(MediaManagerItem):
|
||||||
if check_item_selected(self.list_view, UiStrings().SelectDelete):
|
if check_item_selected(self.list_view, UiStrings().SelectDelete):
|
||||||
items = self.list_view.selectedIndexes()
|
items = self.list_view.selectedIndexes()
|
||||||
if QtGui.QMessageBox.question(self,
|
if QtGui.QMessageBox.question(self,
|
||||||
UiStrings().ConfirmDelete,
|
UiStrings().ConfirmDelete,
|
||||||
translate('CustomPlugin.MediaItem',
|
translate('CustomPlugin.MediaItem',
|
||||||
'Are you sure you want to delete the %n selected custom slide(s)?', '',
|
'Are you sure you want to delete the %n selected custom slide(s)?', '',
|
||||||
QtCore.QCoreApplication.CodecForTr, len(items)),
|
QtCore.QCoreApplication.CodecForTr, len(items)),
|
||||||
QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Yes | QtGui.QMessageBox.No),
|
QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Yes | QtGui.QMessageBox.No),
|
||||||
QtGui.QMessageBox.Yes) == QtGui.QMessageBox.No:
|
QtGui.QMessageBox.Yes) == QtGui.QMessageBox.No:
|
||||||
return
|
return
|
||||||
row_list = [item.row() for item in self.list_view.selectedIndexes()]
|
row_list = [item.row() for item in self.list_view.selectedIndexes()]
|
||||||
row_list.sort(reverse=True)
|
row_list.sort(reverse=True)
|
||||||
id_list = [(item.data(QtCore.Qt.UserRole))
|
id_list = [(item.data(QtCore.Qt.UserRole)) for item in self.list_view.selectedIndexes()]
|
||||||
for item in self.list_view.selectedIndexes()]
|
|
||||||
for id in id_list:
|
for id in id_list:
|
||||||
self.plugin.manager.delete_object(CustomSlide, id)
|
self.plugin.manager.delete_object(CustomSlide, id)
|
||||||
self.on_search_text_button_clicked()
|
self.on_search_text_button_clicked()
|
||||||
|
|
||||||
def onFocus(self):
|
def on_focus(self):
|
||||||
self.search_text_edit.setFocus()
|
self.search_text_edit.setFocus()
|
||||||
|
|
||||||
def generate_slide_data(self, service_item, item=None, xmlVersion=False,
|
def generate_slide_data(self, service_item, item=None, xmlVersion=False,
|
||||||
|
@ -186,20 +185,20 @@ class CustomMediaItem(MediaManagerItem):
|
||||||
"""
|
"""
|
||||||
Generate the slide data. Needs to be implemented by the plugin.
|
Generate the slide data. Needs to be implemented by the plugin.
|
||||||
"""
|
"""
|
||||||
item_id = self._get_id_of_item_to_generate(item, self.remoteCustom)
|
item_id = self._get_id_of_item_to_generate(item, self.remote_custom)
|
||||||
service_item.add_capability(ItemCapabilities.CanEdit)
|
service_item.add_capability(ItemCapabilities.CanEdit)
|
||||||
service_item.add_capability(ItemCapabilities.CanPreview)
|
service_item.add_capability(ItemCapabilities.CanPreview)
|
||||||
service_item.add_capability(ItemCapabilities.CanLoop)
|
service_item.add_capability(ItemCapabilities.CanLoop)
|
||||||
service_item.add_capability(ItemCapabilities.CanSoftBreak)
|
service_item.add_capability(ItemCapabilities.CanSoftBreak)
|
||||||
service_item.add_capability(ItemCapabilities.OnLoadUpdate)
|
service_item.add_capability(ItemCapabilities.OnLoadUpdate)
|
||||||
customSlide = self.plugin.manager.get_object(CustomSlide, item_id)
|
custom_slide = self.plugin.manager.get_object(CustomSlide, item_id)
|
||||||
title = customSlide.title
|
title = custom_slide.title
|
||||||
credit = customSlide.credits
|
credit = custom_slide.credits
|
||||||
service_item.edit_id = item_id
|
service_item.edit_id = item_id
|
||||||
theme = customSlide.theme_name
|
theme = custom_slide.theme_name
|
||||||
if theme:
|
if theme:
|
||||||
service_item.theme = theme
|
service_item.theme = theme
|
||||||
custom_xml = CustomXMLParser(customSlide.text)
|
custom_xml = CustomXMLParser(custom_slide.text)
|
||||||
verse_list = custom_xml.get_verses()
|
verse_list = custom_xml.get_verses()
|
||||||
raw_slides = [verse[1] for verse in verse_list]
|
raw_slides = [verse[1] for verse in verse_list]
|
||||||
service_item.title = title
|
service_item.title = title
|
||||||
|
@ -216,7 +215,6 @@ class CustomMediaItem(MediaManagerItem):
|
||||||
Settings().setValue(u'%s/last search type' % self.settings_section, self.search_text_edit.current_search_type())
|
Settings().setValue(u'%s/last search type' % self.settings_section, self.search_text_edit.current_search_type())
|
||||||
# Reload the list considering the new search type.
|
# Reload the list considering the new search type.
|
||||||
search_keywords = self.search_text_edit.displayText()
|
search_keywords = self.search_text_edit.displayText()
|
||||||
search_results = []
|
|
||||||
search_type = self.search_text_edit.current_search_type()
|
search_type = self.search_text_edit.current_search_type()
|
||||||
if search_type == CustomSearch.Titles:
|
if search_type == CustomSearch.Titles:
|
||||||
log.debug(u'Titles Search')
|
log.debug(u'Titles Search')
|
||||||
|
@ -234,15 +232,14 @@ class CustomMediaItem(MediaManagerItem):
|
||||||
|
|
||||||
def on_search_text_edit_changed(self, text):
|
def on_search_text_edit_changed(self, text):
|
||||||
"""
|
"""
|
||||||
If search as type enabled invoke the search on each key press.
|
If search as type enabled invoke the search on each key press. If the Title is being searched do not start until
|
||||||
If the Title is being searched do not start until 2 characters
|
2 characters have been entered.
|
||||||
have been entered.
|
|
||||||
"""
|
"""
|
||||||
search_length = 2
|
search_length = 2
|
||||||
if len(text) > search_length:
|
if len(text) > search_length:
|
||||||
self.on_search_text_button_clicked()
|
self.on_search_text_button_clicked()
|
||||||
elif not text:
|
elif not text:
|
||||||
self.onClearTextButtonClick()
|
self.on_clear_text_button_click()
|
||||||
|
|
||||||
def service_load(self, item):
|
def service_load(self, item):
|
||||||
"""
|
"""
|
||||||
|
@ -255,7 +252,8 @@ class CustomMediaItem(MediaManagerItem):
|
||||||
and_(CustomSlide.title == item.title, CustomSlide.theme_name == item.theme,
|
and_(CustomSlide.title == item.title, CustomSlide.theme_name == item.theme,
|
||||||
CustomSlide.credits == item.raw_footer[0][len(item.title) + 1:]))
|
CustomSlide.credits == item.raw_footer[0][len(item.title) + 1:]))
|
||||||
if custom:
|
if custom:
|
||||||
self.service_manager.service_item_update(custom.id, item.unique_identifier)
|
item.edit_id = custom.id
|
||||||
|
return item
|
||||||
else:
|
else:
|
||||||
if self.add_custom_from_service:
|
if self.add_custom_from_service:
|
||||||
self.create_from_service_item(item)
|
self.create_from_service_item(item)
|
||||||
|
@ -284,10 +282,8 @@ class CustomMediaItem(MediaManagerItem):
|
||||||
custom.text = unicode(custom_xml.extract_xml(), u'utf-8')
|
custom.text = unicode(custom_xml.extract_xml(), u'utf-8')
|
||||||
self.plugin.manager.save_object(custom)
|
self.plugin.manager.save_object(custom)
|
||||||
self.on_search_text_button_clicked()
|
self.on_search_text_button_clicked()
|
||||||
if item.name.lower() == u'custom':
|
|
||||||
Registry().execute(u'service_item_update', u'%s:%s:%s' % (custom.id, item.unique_identifier, False))
|
|
||||||
|
|
||||||
def onClearTextButtonClick(self):
|
def on_clear_text_button_click(self):
|
||||||
"""
|
"""
|
||||||
Clear the search text.
|
Clear the search text.
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -27,6 +27,6 @@
|
||||||
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
||||||
###############################################################################
|
###############################################################################
|
||||||
"""
|
"""
|
||||||
The :mod:`images` module provides the Images plugin. The Images plugin
|
The :mod:`images` module provides the Images plugin. The Images plugin provides the facility to display images from
|
||||||
provides the facility to display images from OpenLP.
|
OpenLP.
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -27,20 +27,16 @@
|
||||||
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
||||||
###############################################################################
|
###############################################################################
|
||||||
"""
|
"""
|
||||||
Forms in OpenLP are made up of two classes. One class holds all the graphical
|
Forms in OpenLP are made up of two classes. One class holds all the graphical elements, like buttons and lists, and the
|
||||||
elements, like buttons and lists, and the other class holds all the functional
|
other class holds all the functional code, like slots and loading and saving.
|
||||||
code, like slots and loading and saving.
|
|
||||||
|
|
||||||
The first class, commonly known as the **Dialog** class, is typically named
|
The first class, commonly known as the **Dialog** class, is typically named ``Ui_<name>Dialog``. It is a slightly
|
||||||
``Ui_<name>Dialog``. It is a slightly modified version of the class that the
|
modified version of the class that the ``pyuic4`` command produces from Qt4's .ui file. Typical modifications will be
|
||||||
``pyuic4`` command produces from Qt4's .ui file. Typical modifications will be
|
converting most strings from "" to u'' and using OpenLP's ``translate()`` function for translating strings.
|
||||||
converting most strings from "" to u'' and using OpenLP's ``translate()``
|
|
||||||
function for translating strings.
|
|
||||||
|
|
||||||
The second class, commonly known as the **Form** class, is typically named
|
The second class, commonly known as the **Form** class, is typically named ``<name>Form``. This class is the one which
|
||||||
``<name>Form``. This class is the one which is instantiated and used. It uses
|
is instantiated and used. It uses dual inheritance to inherit from (usually) QtGui.QDialog and the Ui class mentioned
|
||||||
dual inheritance to inherit from (usually) QtGui.QDialog and the Ui class
|
above, like so::
|
||||||
mentioned above, like so::
|
|
||||||
|
|
||||||
class AuthorsForm(QtGui.QDialog, Ui_AuthorsDialog):
|
class AuthorsForm(QtGui.QDialog, Ui_AuthorsDialog):
|
||||||
|
|
||||||
|
@ -48,9 +44,8 @@ mentioned above, like so::
|
||||||
QtGui.QDialog.__init__(self, parent)
|
QtGui.QDialog.__init__(self, parent)
|
||||||
self.setupUi(self)
|
self.setupUi(self)
|
||||||
|
|
||||||
This allows OpenLP to use ``self.object`` for all the GUI elements while keeping
|
This allows OpenLP to use ``self.object`` for all the GUI elements while keeping them separate from the functionality,
|
||||||
them separate from the functionality, so that it is easier to recreate the GUI
|
so that it is easier to recreate the GUI from the .ui files later if necessary.
|
||||||
from the .ui files later if necessary.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from addgroupform import AddGroupForm
|
from addgroupform import AddGroupForm
|
||||||
|
|
|
@ -47,16 +47,16 @@ class AddGroupForm(QtGui.QDialog, Ui_AddGroupDialog):
|
||||||
|
|
||||||
def exec_(self, clear=True, show_top_level_group=False, selected_group=None):
|
def exec_(self, clear=True, show_top_level_group=False, selected_group=None):
|
||||||
"""
|
"""
|
||||||
Show the form
|
Show the form.
|
||||||
|
|
||||||
``clear``
|
``clear``
|
||||||
Set to False if the text input box should not be cleared when showing the dialog (default: True)
|
Set to False if the text input box should not be cleared when showing the dialog (default: True).
|
||||||
|
|
||||||
``show_top_level_group``
|
``show_top_level_group``
|
||||||
Set to True when "-- Top level group --" should be showed as first item (default: False)
|
Set to True when "-- Top level group --" should be showed as first item (default: False).
|
||||||
|
|
||||||
``selected_group``
|
``selected_group``
|
||||||
The ID of the group that should be selected by default when showing the dialog
|
The ID of the group that should be selected by default when showing the dialog.
|
||||||
"""
|
"""
|
||||||
if clear:
|
if clear:
|
||||||
self.name_edit.clear()
|
self.name_edit.clear()
|
||||||
|
@ -72,7 +72,7 @@ class AddGroupForm(QtGui.QDialog, Ui_AddGroupDialog):
|
||||||
|
|
||||||
def accept(self):
|
def accept(self):
|
||||||
"""
|
"""
|
||||||
Override the accept() method from QDialog to make sure something is entered in the text input box
|
Override the accept() method from QDialog to make sure something is entered in the text input box.
|
||||||
"""
|
"""
|
||||||
if not self.name_edit.text():
|
if not self.name_edit.text():
|
||||||
critical_error_message_box(message=translate('ImagePlugin.AddGroupForm',
|
critical_error_message_box(message=translate('ImagePlugin.AddGroupForm',
|
||||||
|
|
|
@ -48,10 +48,11 @@ class ChooseGroupForm(QtGui.QDialog, Ui_ChooseGroupDialog):
|
||||||
Show the form
|
Show the form
|
||||||
|
|
||||||
``selected_group``
|
``selected_group``
|
||||||
The ID of the group that should be selected by default when showing the dialog
|
The ID of the group that should be selected by default when showing the dialog.
|
||||||
"""
|
"""
|
||||||
|
self.new_group_edit.clear()
|
||||||
if selected_group is not None:
|
if selected_group is not None:
|
||||||
for i in range(self.group_combobox.count()):
|
for index in range(self.group_combobox.count()):
|
||||||
if self.group_combobox.itemData(i) == selected_group:
|
if self.group_combobox.itemData(index) == selected_group:
|
||||||
self.group_combobox.setCurrentIndex(i)
|
self.group_combobox.setCurrentIndex(index)
|
||||||
return QtGui.QDialog.exec_(self)
|
return QtGui.QDialog.exec_(self)
|
||||||
|
|
|
@ -70,10 +70,10 @@ class ImagePlugin(Plugin):
|
||||||
|
|
||||||
def app_startup(self):
|
def app_startup(self):
|
||||||
"""
|
"""
|
||||||
Perform tasks on application startup
|
Perform tasks on application startup.
|
||||||
"""
|
"""
|
||||||
Plugin.app_startup(self)
|
Plugin.app_startup(self)
|
||||||
# Convert old settings-based image list to the database
|
# Convert old settings-based image list to the database.
|
||||||
files_from_config = Settings().get_files_from_config(self)
|
files_from_config = Settings().get_files_from_config(self)
|
||||||
if files_from_config:
|
if files_from_config:
|
||||||
log.debug(u'Importing images list from old config: %s' % files_from_config)
|
log.debug(u'Importing images list from old config: %s' % files_from_config)
|
||||||
|
@ -93,7 +93,7 @@ class ImagePlugin(Plugin):
|
||||||
|
|
||||||
def set_plugin_text_strings(self):
|
def set_plugin_text_strings(self):
|
||||||
"""
|
"""
|
||||||
Called to define all translatable texts of the plugin
|
Called to define all translatable texts of the plugin.
|
||||||
"""
|
"""
|
||||||
## Name PluginList ##
|
## Name PluginList ##
|
||||||
self.text_strings[StringContent.Name] = {
|
self.text_strings[StringContent.Name] = {
|
||||||
|
@ -117,8 +117,8 @@ class ImagePlugin(Plugin):
|
||||||
|
|
||||||
def config_update(self):
|
def config_update(self):
|
||||||
"""
|
"""
|
||||||
Triggered by saving and changing the image border. Sets the images in image manager to require updates.
|
Triggered by saving and changing the image border. Sets the images in image manager to require updates. Actual
|
||||||
Actual update is triggered by the last part of saving the config.
|
update is triggered by the last part of saving the config.
|
||||||
"""
|
"""
|
||||||
log.info(u'Images config_update')
|
log.info(u'Images config_update')
|
||||||
background = QtGui.QColor(Settings().value(self.settings_section + u'/background color'))
|
background = QtGui.QColor(Settings().value(self.settings_section + u'/background color'))
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
||||||
###############################################################################
|
###############################################################################
|
||||||
"""
|
"""
|
||||||
The :mod:`db` module provides the database and schema that is the backend for the Images plugin
|
The :mod:`db` module provides the database and schema that is the backend for the Images plugin.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from sqlalchemy import Column, ForeignKey, Table, types
|
from sqlalchemy import Column, ForeignKey, Table, types
|
||||||
|
@ -38,14 +38,14 @@ from openlp.core.lib.db import BaseModel, init_db
|
||||||
|
|
||||||
class ImageGroups(BaseModel):
|
class ImageGroups(BaseModel):
|
||||||
"""
|
"""
|
||||||
ImageGroups model
|
ImageGroups model.
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class ImageFilenames(BaseModel):
|
class ImageFilenames(BaseModel):
|
||||||
"""
|
"""
|
||||||
ImageFilenames model
|
ImageFilenames model.
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,6 @@ from PyQt4 import QtGui
|
||||||
from openlp.core.lib import Registry, SettingsTab, Settings, UiStrings, translate
|
from openlp.core.lib import Registry, SettingsTab, Settings, UiStrings, translate
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class ImageTab(SettingsTab):
|
class ImageTab(SettingsTab):
|
||||||
"""
|
"""
|
||||||
ImageTab is the images settings tab in the settings dialog.
|
ImageTab is the images settings tab in the settings dialog.
|
||||||
|
|
|
@ -40,6 +40,7 @@ from openlp.core.utils import AppLocation, delete_file, get_locale_key, get_imag
|
||||||
from openlp.plugins.images.forms import AddGroupForm, ChooseGroupForm
|
from openlp.plugins.images.forms import AddGroupForm, ChooseGroupForm
|
||||||
from openlp.plugins.images.lib.db import ImageFilenames, ImageGroups
|
from openlp.plugins.images.lib.db import ImageFilenames, ImageGroups
|
||||||
|
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
@ -60,24 +61,23 @@ class ImageMediaItem(MediaManagerItem):
|
||||||
self.fill_groups_combobox(self.choose_group_form.group_combobox)
|
self.fill_groups_combobox(self.choose_group_form.group_combobox)
|
||||||
self.fill_groups_combobox(self.add_group_form.parent_group_combobox)
|
self.fill_groups_combobox(self.add_group_form.parent_group_combobox)
|
||||||
Registry().register_function(u'live_theme_changed', self.live_theme_changed)
|
Registry().register_function(u'live_theme_changed', self.live_theme_changed)
|
||||||
# Allow DnD from the desktop
|
# Allow DnD from the desktop.
|
||||||
self.list_view.activateDnD()
|
self.list_view.activateDnD()
|
||||||
|
|
||||||
def retranslateUi(self):
|
def retranslateUi(self):
|
||||||
self.on_new_prompt = translate('ImagePlugin.MediaItem',
|
self.on_new_prompt = translate('ImagePlugin.MediaItem', 'Select Image(s)')
|
||||||
'Select Image(s)')
|
|
||||||
file_formats = get_images_filter()
|
file_formats = get_images_filter()
|
||||||
self.on_new_file_masks = u'%s;;%s (*.*) (*)' % (file_formats, UiStrings().AllFiles)
|
self.on_new_file_masks = u'%s;;%s (*.*) (*)' % (file_formats, UiStrings().AllFiles)
|
||||||
self.addGroupAction.setText(UiStrings().AddGroup)
|
self.addGroupAction.setText(UiStrings().AddGroup)
|
||||||
self.addGroupAction.setToolTip(UiStrings().AddGroup)
|
self.addGroupAction.setToolTip(UiStrings().AddGroup)
|
||||||
self.replaceAction.setText(UiStrings().ReplaceBG)
|
self.replace_action.setText(UiStrings().ReplaceBG)
|
||||||
self.replaceAction.setToolTip(UiStrings().ReplaceLiveBG)
|
self.replace_action.setToolTip(UiStrings().ReplaceLiveBG)
|
||||||
self.resetAction.setText(UiStrings().ResetBG)
|
self.reset_action.setText(UiStrings().ResetBG)
|
||||||
self.resetAction.setToolTip(UiStrings().ResetLiveBG)
|
self.reset_action.setToolTip(UiStrings().ResetLiveBG)
|
||||||
|
|
||||||
def required_icons(self):
|
def required_icons(self):
|
||||||
"""
|
"""
|
||||||
Set which icons the media manager tab should show
|
Set which icons the media manager tab should show.
|
||||||
"""
|
"""
|
||||||
MediaManagerItem.required_icons(self)
|
MediaManagerItem.required_icons(self)
|
||||||
self.has_file_icon = True
|
self.has_file_icon = True
|
||||||
|
@ -94,13 +94,13 @@ class ImageMediaItem(MediaManagerItem):
|
||||||
self.servicePath = os.path.join(AppLocation.get_section_data_path(self.settings_section), u'thumbnails')
|
self.servicePath = os.path.join(AppLocation.get_section_data_path(self.settings_section), u'thumbnails')
|
||||||
check_directory_exists(self.servicePath)
|
check_directory_exists(self.servicePath)
|
||||||
# Load images from the database
|
# Load images from the database
|
||||||
self.loadFullList(
|
self.load_full_list(
|
||||||
self.manager.get_all_objects(ImageFilenames, order_by_ref=ImageFilenames.filename), initial_load=True)
|
self.manager.get_all_objects(ImageFilenames, order_by_ref=ImageFilenames.filename), initial_load=True)
|
||||||
|
|
||||||
def add_list_view_to_toolbar(self):
|
def add_list_view_to_toolbar(self):
|
||||||
"""
|
"""
|
||||||
Creates the main widget for listing items the media item is tracking.
|
Creates the main widget for listing items the media item is tracking. This method overloads
|
||||||
This method overloads MediaManagerItem.add_list_view_to_toolbar
|
MediaManagerItem.add_list_view_to_toolbar.
|
||||||
"""
|
"""
|
||||||
# Add the List widget
|
# Add the List widget
|
||||||
self.list_view = TreeWidgetWithDnD(self, self.plugin.name)
|
self.list_view = TreeWidgetWithDnD(self, self.plugin.name)
|
||||||
|
@ -155,44 +155,41 @@ class ImageMediaItem(MediaManagerItem):
|
||||||
self.list_view.doubleClicked.connect(self.on_double_clicked)
|
self.list_view.doubleClicked.connect(self.on_double_clicked)
|
||||||
self.list_view.itemSelectionChanged.connect(self.on_selection_change)
|
self.list_view.itemSelectionChanged.connect(self.on_selection_change)
|
||||||
self.list_view.customContextMenuRequested.connect(self.context_menu)
|
self.list_view.customContextMenuRequested.connect(self.context_menu)
|
||||||
self.list_view.addAction(self.replaceAction)
|
self.list_view.addAction(self.replace_action)
|
||||||
|
|
||||||
def add_custom_context_actions(self):
|
def add_custom_context_actions(self):
|
||||||
"""
|
"""
|
||||||
Add custom actions to the context menu
|
Add custom actions to the context menu.
|
||||||
"""
|
"""
|
||||||
create_widget_action(self.list_view, separator=True)
|
create_widget_action(self.list_view, separator=True)
|
||||||
create_widget_action(self.list_view,
|
create_widget_action(self.list_view,
|
||||||
text=UiStrings().AddGroup,
|
text=UiStrings().AddGroup, icon=u':/images/image_new_group.png', triggers=self.on_add_group_click)
|
||||||
icon=u':/images/image_new_group.png',
|
|
||||||
triggers=self.onAddGroupClick)
|
|
||||||
create_widget_action(self.list_view,
|
create_widget_action(self.list_view,
|
||||||
text=self.plugin.get_string(StringContent.Load)[u'tooltip'],
|
text=self.plugin.get_string(StringContent.Load)[u'tooltip'],
|
||||||
icon=u':/general/general_open.png',
|
icon=u':/general/general_open.png', triggers=self.on_file_click)
|
||||||
triggers=self.on_file_click)
|
|
||||||
|
|
||||||
def add_start_header_bar(self):
|
def add_start_header_bar(self):
|
||||||
"""
|
"""
|
||||||
Add custom buttons to the start of the toolbar
|
Add custom buttons to the start of the toolbar.
|
||||||
"""
|
"""
|
||||||
self.addGroupAction = self.toolbar.add_toolbar_action(u'addGroupAction',
|
self.addGroupAction = self.toolbar.add_toolbar_action(u'addGroupAction',
|
||||||
icon=u':/images/image_new_group.png', triggers=self.onAddGroupClick)
|
icon=u':/images/image_new_group.png', triggers=self.on_add_group_click)
|
||||||
|
|
||||||
def add_end_header_bar(self):
|
def add_end_header_bar(self):
|
||||||
"""
|
"""
|
||||||
Add custom buttons to the end of the toolbar
|
Add custom buttons to the end of the toolbar
|
||||||
"""
|
"""
|
||||||
self.replaceAction = self.toolbar.add_toolbar_action(u'replaceAction',
|
self.replace_action = self.toolbar.add_toolbar_action(u'replace_action',
|
||||||
icon=u':/slides/slide_blank.png', triggers=self.onReplaceClick)
|
icon=u':/slides/slide_blank.png', triggers=self.on_replace_click)
|
||||||
self.resetAction = self.toolbar.add_toolbar_action(u'resetAction',
|
self.reset_action = self.toolbar.add_toolbar_action(u'reset_action',
|
||||||
icon=u':/system/system_close.png', visible=False, triggers=self.onResetClick)
|
icon=u':/system/system_close.png', visible=False, triggers=self.on_reset_click)
|
||||||
|
|
||||||
def recursively_delete_group(self, image_group):
|
def recursively_delete_group(self, image_group):
|
||||||
"""
|
"""
|
||||||
Recursively deletes a group and all groups and images in it
|
Recursively deletes a group and all groups and images in it.
|
||||||
|
|
||||||
``image_group``
|
``image_group``
|
||||||
The ImageGroups instance of the group that will be deleted
|
The ImageGroups instance of the group that will be deleted.
|
||||||
"""
|
"""
|
||||||
images = self.manager.get_all_objects(ImageFilenames, ImageFilenames.group_id == image_group.id)
|
images = self.manager.get_all_objects(ImageFilenames, ImageFilenames.group_id == image_group.id)
|
||||||
for image in images:
|
for image in images:
|
||||||
|
@ -205,7 +202,7 @@ class ImageMediaItem(MediaManagerItem):
|
||||||
|
|
||||||
def on_delete_click(self):
|
def on_delete_click(self):
|
||||||
"""
|
"""
|
||||||
Remove an image item from the list
|
Remove an image item from the list.
|
||||||
"""
|
"""
|
||||||
# Turn off auto preview triggers.
|
# Turn off auto preview triggers.
|
||||||
self.list_view.blockSignals(True)
|
self.list_view.blockSignals(True)
|
||||||
|
@ -226,11 +223,11 @@ class ImageMediaItem(MediaManagerItem):
|
||||||
self.manager.delete_object(ImageFilenames, row_item.data(0, QtCore.Qt.UserRole).id)
|
self.manager.delete_object(ImageFilenames, row_item.data(0, QtCore.Qt.UserRole).id)
|
||||||
elif isinstance(item_data, ImageGroups):
|
elif isinstance(item_data, ImageGroups):
|
||||||
if QtGui.QMessageBox.question(self.list_view.parent(),
|
if QtGui.QMessageBox.question(self.list_view.parent(),
|
||||||
translate('ImagePlugin.MediaItem', 'Remove group'),
|
translate('ImagePlugin.MediaItem', 'Remove group'),
|
||||||
translate('ImagePlugin.MediaItem',
|
translate('ImagePlugin.MediaItem',
|
||||||
'Are you sure you want to remove "%s" and everything in it?') % item_data.group_name,
|
'Are you sure you want to remove "%s" and everything in it?') % item_data.group_name,
|
||||||
QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Yes |
|
QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Yes |
|
||||||
QtGui.QMessageBox.No)) == QtGui.QMessageBox.Yes:
|
QtGui.QMessageBox.No)) == QtGui.QMessageBox.Yes:
|
||||||
self.recursively_delete_group(item_data)
|
self.recursively_delete_group(item_data)
|
||||||
self.manager.delete_object(ImageGroups, row_item.data(0, QtCore.Qt.UserRole).id)
|
self.manager.delete_object(ImageGroups, row_item.data(0, QtCore.Qt.UserRole).id)
|
||||||
if item_data.parent_id == 0:
|
if item_data.parent_id == 0:
|
||||||
|
@ -246,13 +243,13 @@ class ImageMediaItem(MediaManagerItem):
|
||||||
|
|
||||||
def add_sub_groups(self, group_list, parent_group_id):
|
def add_sub_groups(self, group_list, parent_group_id):
|
||||||
"""
|
"""
|
||||||
Recursively add subgroups to the given parent group in a QTreeWidget
|
Recursively add subgroups to the given parent group in a QTreeWidget.
|
||||||
|
|
||||||
``group_list``
|
``group_list``
|
||||||
The List object that contains all QTreeWidgetItems
|
The List object that contains all QTreeWidgetItems.
|
||||||
|
|
||||||
``parent_group_id``
|
``parent_group_id``
|
||||||
The ID of the group that will be added recursively
|
The ID of the group that will be added recursively.
|
||||||
"""
|
"""
|
||||||
image_groups = self.manager.get_all_objects(ImageGroups, ImageGroups.parent_id == parent_group_id)
|
image_groups = self.manager.get_all_objects(ImageGroups, ImageGroups.parent_id == parent_group_id)
|
||||||
image_groups.sort(key=lambda group_object: get_locale_key(group_object.group_name))
|
image_groups.sort(key=lambda group_object: get_locale_key(group_object.group_name))
|
||||||
|
@ -271,16 +268,16 @@ class ImageMediaItem(MediaManagerItem):
|
||||||
|
|
||||||
def fill_groups_combobox(self, combobox, parent_group_id=0, prefix=''):
|
def fill_groups_combobox(self, combobox, parent_group_id=0, prefix=''):
|
||||||
"""
|
"""
|
||||||
Recursively add groups to the combobox in the 'Add group' dialog
|
Recursively add groups to the combobox in the 'Add group' dialog.
|
||||||
|
|
||||||
``combobox``
|
``combobox``
|
||||||
The QComboBox to add the options to
|
The QComboBox to add the options to.
|
||||||
|
|
||||||
``parent_group_id``
|
``parent_group_id``
|
||||||
The ID of the group that will be added
|
The ID of the group that will be added.
|
||||||
|
|
||||||
``prefix``
|
``prefix``
|
||||||
A string containing the prefix that will be added in front of the groupname for each level of the tree
|
A string containing the prefix that will be added in front of the groupname for each level of the tree.
|
||||||
"""
|
"""
|
||||||
if parent_group_id == 0:
|
if parent_group_id == 0:
|
||||||
combobox.clear()
|
combobox.clear()
|
||||||
|
@ -293,13 +290,13 @@ class ImageMediaItem(MediaManagerItem):
|
||||||
|
|
||||||
def expand_group(self, group_id, root_item=None):
|
def expand_group(self, group_id, root_item=None):
|
||||||
"""
|
"""
|
||||||
Expand groups in the widget recursively
|
Expand groups in the widget recursively.
|
||||||
|
|
||||||
``group_id``
|
``group_id``
|
||||||
The ID of the group that will be expanded
|
The ID of the group that will be expanded.
|
||||||
|
|
||||||
``root_item``
|
``root_item``
|
||||||
This option is only used for recursion purposes
|
This option is only used for recursion purposes.
|
||||||
"""
|
"""
|
||||||
return_value = False
|
return_value = False
|
||||||
if root_item is None:
|
if root_item is None:
|
||||||
|
@ -314,29 +311,29 @@ class ImageMediaItem(MediaManagerItem):
|
||||||
return True
|
return True
|
||||||
return return_value
|
return return_value
|
||||||
|
|
||||||
def loadFullList(self, images, initial_load=False, open_group=None):
|
def load_full_list(self, images, initial_load=False, open_group=None):
|
||||||
"""
|
"""
|
||||||
Replace the list of images and groups in the interface.
|
Replace the list of images and groups in the interface.
|
||||||
|
|
||||||
``images``
|
``images``
|
||||||
A List of ImageFilenames objects that will be used to reload the mediamanager list
|
A List of ImageFilenames objects that will be used to reload the mediamanager list.
|
||||||
|
|
||||||
``initial_load``
|
``initial_load``
|
||||||
When set to False, the busy cursor and progressbar will be shown while loading images
|
When set to False, the busy cursor and progressbar will be shown while loading images.
|
||||||
|
|
||||||
``open_group``
|
``open_group``
|
||||||
ImageGroups object of the group that must be expanded after reloading the list in the interface
|
ImageGroups object of the group that must be expanded after reloading the list in the interface.
|
||||||
"""
|
"""
|
||||||
if not initial_load:
|
if not initial_load:
|
||||||
self.application.set_busy_cursor()
|
self.application.set_busy_cursor()
|
||||||
self.main_window.display_progress_bar(len(images))
|
self.main_window.display_progress_bar(len(images))
|
||||||
self.list_view.clear()
|
self.list_view.clear()
|
||||||
# Load the list of groups and add them to the treeView
|
# Load the list of groups and add them to the treeView.
|
||||||
group_items = {}
|
group_items = {}
|
||||||
self.add_sub_groups(group_items, parent_group_id=0)
|
self.add_sub_groups(group_items, parent_group_id=0)
|
||||||
if open_group is not None:
|
if open_group is not None:
|
||||||
self.expand_group(open_group.id)
|
self.expand_group(open_group.id)
|
||||||
# Sort the images by its filename considering language specific
|
# Sort the images by its filename considering language specific.
|
||||||
# characters.
|
# characters.
|
||||||
images.sort(key=lambda image_object: get_locale_key(os.path.split(unicode(image_object.filename))[1]))
|
images.sort(key=lambda image_object: get_locale_key(os.path.split(unicode(image_object.filename))[1]))
|
||||||
for imageFile in images:
|
for imageFile in images:
|
||||||
|
@ -394,6 +391,7 @@ class ImageMediaItem(MediaManagerItem):
|
||||||
``initial_load``
|
``initial_load``
|
||||||
When set to False, the busy cursor and progressbar will be shown while loading images
|
When set to False, the busy cursor and progressbar will be shown while loading images
|
||||||
"""
|
"""
|
||||||
|
parent_group = None
|
||||||
if target_group is None:
|
if target_group is None:
|
||||||
# Find out if a group must be pre-selected
|
# Find out if a group must be pre-selected
|
||||||
preselect_group = None
|
preselect_group = None
|
||||||
|
@ -439,6 +437,8 @@ class ImageMediaItem(MediaManagerItem):
|
||||||
parent_group.parent_id = 0
|
parent_group.parent_id = 0
|
||||||
parent_group.group_name = self.choose_group_form.new_group_edit.text()
|
parent_group.group_name = self.choose_group_form.new_group_edit.text()
|
||||||
self.manager.save_object(parent_group)
|
self.manager.save_object(parent_group)
|
||||||
|
self.fill_groups_combobox(self.choose_group_form.group_combobox)
|
||||||
|
self.fill_groups_combobox(self.add_group_form.parent_group_combobox)
|
||||||
else:
|
else:
|
||||||
parent_group = target_group.data(0, QtCore.Qt.UserRole)
|
parent_group = target_group.data(0, QtCore.Qt.UserRole)
|
||||||
if isinstance(parent_group, ImageFilenames):
|
if isinstance(parent_group, ImageFilenames):
|
||||||
|
@ -455,7 +455,7 @@ class ImageMediaItem(MediaManagerItem):
|
||||||
self.main_window.display_progress_bar(len(images))
|
self.main_window.display_progress_bar(len(images))
|
||||||
# Save the new images in the database
|
# Save the new images in the database
|
||||||
self.save_new_images_list(images, group_id=parent_group.id, reload_list=False)
|
self.save_new_images_list(images, group_id=parent_group.id, reload_list=False)
|
||||||
self.loadFullList(self.manager.get_all_objects(ImageFilenames, order_by_ref=ImageFilenames.filename),
|
self.load_full_list(self.manager.get_all_objects(ImageFilenames, order_by_ref=ImageFilenames.filename),
|
||||||
initial_load=initial_load, open_group=parent_group)
|
initial_load=initial_load, open_group=parent_group)
|
||||||
self.application.set_normal_cursor()
|
self.application.set_normal_cursor()
|
||||||
|
|
||||||
|
@ -482,7 +482,7 @@ class ImageMediaItem(MediaManagerItem):
|
||||||
self.manager.save_object(imageFile)
|
self.manager.save_object(imageFile)
|
||||||
self.main_window.increment_progress_bar()
|
self.main_window.increment_progress_bar()
|
||||||
if reload_list and images_list:
|
if reload_list and images_list:
|
||||||
self.loadFullList(self.manager.get_all_objects(ImageFilenames, order_by_ref=ImageFilenames.filename))
|
self.load_full_list(self.manager.get_all_objects(ImageFilenames, order_by_ref=ImageFilenames.filename))
|
||||||
|
|
||||||
def dnd_move_internal(self, target):
|
def dnd_move_internal(self, target):
|
||||||
"""
|
"""
|
||||||
|
@ -530,7 +530,7 @@ class ImageMediaItem(MediaManagerItem):
|
||||||
image_items.sort(key=lambda item: get_locale_key(item.text(0)))
|
image_items.sort(key=lambda item: get_locale_key(item.text(0)))
|
||||||
target_group.addChildren(image_items)
|
target_group.addChildren(image_items)
|
||||||
|
|
||||||
def generate_slide_data(self, service_item, item=None, xmlVersion=False,
|
def generate_slide_data(self, service_item, item=None, xml_version=False,
|
||||||
remote=False, context=ServiceItemContext.Service):
|
remote=False, context=ServiceItemContext.Service):
|
||||||
"""
|
"""
|
||||||
Generate the slide data. Needs to be implemented by the plugin.
|
Generate the slide data. Needs to be implemented by the plugin.
|
||||||
|
@ -553,28 +553,25 @@ class ImageMediaItem(MediaManagerItem):
|
||||||
service_item.add_capability(ItemCapabilities.CanAppend)
|
service_item.add_capability(ItemCapabilities.CanAppend)
|
||||||
# force a nonexistent theme
|
# force a nonexistent theme
|
||||||
service_item.theme = -1
|
service_item.theme = -1
|
||||||
missing_items = []
|
|
||||||
missing_items_filenames = []
|
missing_items_filenames = []
|
||||||
|
images_filenames = []
|
||||||
# Expand groups to images
|
# Expand groups to images
|
||||||
for bitem in items:
|
for bitem in items:
|
||||||
if isinstance(bitem.data(0, QtCore.Qt.UserRole), ImageGroups) or bitem.data(0, QtCore.Qt.UserRole) is None:
|
if isinstance(bitem.data(0, QtCore.Qt.UserRole), ImageGroups) or bitem.data(0, QtCore.Qt.UserRole) is None:
|
||||||
for index in range(0, bitem.childCount()):
|
for index in range(0, bitem.childCount()):
|
||||||
if isinstance(bitem.child(index).data(0, QtCore.Qt.UserRole), ImageFilenames):
|
if isinstance(bitem.child(index).data(0, QtCore.Qt.UserRole), ImageFilenames):
|
||||||
items.append(bitem.child(index))
|
images_filenames.append(bitem.child(index).data(0, QtCore.Qt.UserRole).filename)
|
||||||
items.remove(bitem)
|
elif isinstance(bitem.data(0, QtCore.Qt.UserRole), ImageFilenames):
|
||||||
|
images_filenames.append(bitem.data(0, QtCore.Qt.UserRole).filename)
|
||||||
# Don't try to display empty groups
|
# Don't try to display empty groups
|
||||||
if not items:
|
if not images_filenames:
|
||||||
return False
|
return False
|
||||||
# Find missing files
|
# Find missing files
|
||||||
for bitem in items:
|
for filename in images_filenames:
|
||||||
filename = bitem.data(0, QtCore.Qt.UserRole).filename
|
|
||||||
if not os.path.exists(filename):
|
if not os.path.exists(filename):
|
||||||
missing_items.append(bitem)
|
|
||||||
missing_items_filenames.append(filename)
|
missing_items_filenames.append(filename)
|
||||||
for item in missing_items:
|
|
||||||
items.remove(item)
|
|
||||||
# We cannot continue, as all images do not exist.
|
# We cannot continue, as all images do not exist.
|
||||||
if not items:
|
if not images_filenames:
|
||||||
if not remote:
|
if not remote:
|
||||||
critical_error_message_box(
|
critical_error_message_box(
|
||||||
translate('ImagePlugin.MediaItem', 'Missing Image(s)'),
|
translate('ImagePlugin.MediaItem', 'Missing Image(s)'),
|
||||||
|
@ -582,15 +579,14 @@ class ImageMediaItem(MediaManagerItem):
|
||||||
u'\n'.join(missing_items_filenames))
|
u'\n'.join(missing_items_filenames))
|
||||||
return False
|
return False
|
||||||
# We have missing as well as existing images. We ask what to do.
|
# We have missing as well as existing images. We ask what to do.
|
||||||
elif missing_items and QtGui.QMessageBox.question(self,
|
elif missing_items_filenames and QtGui.QMessageBox.question(self,
|
||||||
translate('ImagePlugin.MediaItem', 'Missing Image(s)'),
|
translate('ImagePlugin.MediaItem', 'Missing Image(s)'),
|
||||||
translate('ImagePlugin.MediaItem', 'The following image(s) no longer exist: %s\n'
|
translate('ImagePlugin.MediaItem', 'The following image(s) no longer exist: %s\n'
|
||||||
'Do you want to add the other images anyway?') % u'\n'.join(missing_items_filenames),
|
'Do you want to add the other images anyway?') % u'\n'.join(missing_items_filenames),
|
||||||
QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.No | QtGui.QMessageBox.Yes)) == QtGui.QMessageBox.No:
|
QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.No | QtGui.QMessageBox.Yes)) == QtGui.QMessageBox.No:
|
||||||
return False
|
return False
|
||||||
# Continue with the existing images.
|
# Continue with the existing images.
|
||||||
for bitem in items:
|
for filename in images_filenames:
|
||||||
filename = bitem.data(0, QtCore.Qt.UserRole).filename
|
|
||||||
name = os.path.split(filename)[1]
|
name = os.path.split(filename)[1]
|
||||||
service_item.add_from_image(filename, name, background)
|
service_item.add_from_image(filename, name, background)
|
||||||
return True
|
return True
|
||||||
|
@ -608,7 +604,7 @@ class ImageMediaItem(MediaManagerItem):
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def onAddGroupClick(self):
|
def on_add_group_click(self):
|
||||||
"""
|
"""
|
||||||
Called to add a new group
|
Called to add a new group
|
||||||
"""
|
"""
|
||||||
|
@ -629,7 +625,7 @@ class ImageMediaItem(MediaManagerItem):
|
||||||
group_name=self.add_group_form.name_edit.text())
|
group_name=self.add_group_form.name_edit.text())
|
||||||
if not self.check_group_exists(new_group):
|
if not self.check_group_exists(new_group):
|
||||||
if self.manager.save_object(new_group):
|
if self.manager.save_object(new_group):
|
||||||
self.loadFullList(self.manager.get_all_objects(ImageFilenames,
|
self.load_full_list(self.manager.get_all_objects(ImageFilenames,
|
||||||
order_by_ref=ImageFilenames.filename))
|
order_by_ref=ImageFilenames.filename))
|
||||||
self.expand_group(new_group.id)
|
self.expand_group(new_group.id)
|
||||||
self.fill_groups_combobox(self.choose_group_form.group_combobox)
|
self.fill_groups_combobox(self.choose_group_form.group_combobox)
|
||||||
|
@ -638,23 +634,22 @@ class ImageMediaItem(MediaManagerItem):
|
||||||
critical_error_message_box(
|
critical_error_message_box(
|
||||||
message=translate('ImagePlugin.AddGroupForm', 'Could not add the new group.'))
|
message=translate('ImagePlugin.AddGroupForm', 'Could not add the new group.'))
|
||||||
else:
|
else:
|
||||||
critical_error_message_box(
|
critical_error_message_box(message=translate('ImagePlugin.AddGroupForm', 'This group already exists.'))
|
||||||
message=translate('ImagePlugin.AddGroupForm', 'This group already exists.'))
|
|
||||||
|
|
||||||
def onResetClick(self):
|
def on_reset_click(self):
|
||||||
"""
|
"""
|
||||||
Called to reset the Live background with the image selected,
|
Called to reset the Live background with the image selected.
|
||||||
"""
|
"""
|
||||||
self.resetAction.setVisible(False)
|
self.reset_action.setVisible(False)
|
||||||
self.live_controller.display.reset_image()
|
self.live_controller.display.reset_image()
|
||||||
|
|
||||||
def live_theme_changed(self):
|
def live_theme_changed(self):
|
||||||
"""
|
"""
|
||||||
Triggered by the change of theme in the slide controller
|
Triggered by the change of theme in the slide controller.
|
||||||
"""
|
"""
|
||||||
self.resetAction.setVisible(False)
|
self.reset_action.setVisible(False)
|
||||||
|
|
||||||
def onReplaceClick(self):
|
def on_replace_click(self):
|
||||||
"""
|
"""
|
||||||
Called to replace Live backgound with the image selected.
|
Called to replace Live backgound with the image selected.
|
||||||
"""
|
"""
|
||||||
|
@ -663,12 +658,12 @@ class ImageMediaItem(MediaManagerItem):
|
||||||
background = QtGui.QColor(Settings().value(self.settings_section + u'/background color'))
|
background = QtGui.QColor(Settings().value(self.settings_section + u'/background color'))
|
||||||
bitem = self.list_view.selectedItems()[0]
|
bitem = self.list_view.selectedItems()[0]
|
||||||
if not isinstance(bitem.data(0, QtCore.Qt.UserRole), ImageFilenames):
|
if not isinstance(bitem.data(0, QtCore.Qt.UserRole), ImageFilenames):
|
||||||
# Only continue when an image is selected
|
# Only continue when an image is selected.
|
||||||
return
|
return
|
||||||
filename = bitem.data(0, QtCore.Qt.UserRole).filename
|
filename = bitem.data(0, QtCore.Qt.UserRole).filename
|
||||||
if os.path.exists(filename):
|
if os.path.exists(filename):
|
||||||
if self.live_controller.display.direct_image(filename, background):
|
if self.live_controller.display.direct_image(filename, background):
|
||||||
self.resetAction.setVisible(True)
|
self.reset_action.setVisible(True)
|
||||||
else:
|
else:
|
||||||
critical_error_message_box(UiStrings().LiveBGError,
|
critical_error_message_box(UiStrings().LiveBGError,
|
||||||
translate('ImagePlugin.MediaItem', 'There was no display item to amend.'))
|
translate('ImagePlugin.MediaItem', 'There was no display item to amend.'))
|
||||||
|
|
|
@ -27,8 +27,7 @@
|
||||||
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
||||||
###############################################################################
|
###############################################################################
|
||||||
"""
|
"""
|
||||||
The :mod:`media` module provides the Media plugin which allows OpenLP to
|
The :mod:`media` module provides the Media plugin which allows OpenLP to display videos. The media supported depends not
|
||||||
display videos. The media supported depends not only on the Python support
|
only on the Python support but also extensively on the codecs installed on the underlying operating system being picked
|
||||||
but also extensively on the codecs installed on the underlying operating system
|
up and usable by Python.
|
||||||
being picked up and usable by Python.
|
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -39,13 +39,16 @@ from openlp.core.ui import DisplayController, Display, DisplayControllerType
|
||||||
from openlp.core.ui.media import get_media_players, set_media_players
|
from openlp.core.ui.media import get_media_players, set_media_players
|
||||||
from openlp.core.utils import AppLocation, get_locale_key
|
from openlp.core.utils import AppLocation, get_locale_key
|
||||||
|
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
CLAPPERBOARD = u':/media/slidecontroller_multimedia.png'
|
CLAPPERBOARD = u':/media/slidecontroller_multimedia.png'
|
||||||
VIDEO = build_icon(QtGui.QImage(u':/media/media_video.png'))
|
VIDEO_ICON = build_icon(u':/media/media_video.png')
|
||||||
AUDIO = build_icon(QtGui.QImage(u':/media/media_audio.png'))
|
AUDIO_ICON = build_icon(u':/media/media_audio.png')
|
||||||
DVDICON = build_icon(QtGui.QImage(u':/media/media_video.png'))
|
DVD_ICON = build_icon(u':/media/media_video.png')
|
||||||
ERROR = build_icon(QtGui.QImage(u':/general/general_delete.png'))
|
ERROR_ICON = build_icon(u':/general/general_delete.png')
|
||||||
|
|
||||||
|
|
||||||
class MediaMediaItem(MediaManagerItem):
|
class MediaMediaItem(MediaManagerItem):
|
||||||
"""
|
"""
|
||||||
|
@ -79,12 +82,12 @@ class MediaMediaItem(MediaManagerItem):
|
||||||
|
|
||||||
def retranslateUi(self):
|
def retranslateUi(self):
|
||||||
self.on_new_prompt = translate('MediaPlugin.MediaItem', 'Select Media')
|
self.on_new_prompt = translate('MediaPlugin.MediaItem', 'Select Media')
|
||||||
self.replaceAction.setText(UiStrings().ReplaceBG)
|
self.replace_action.setText(UiStrings().ReplaceBG)
|
||||||
self.replaceAction.setToolTip(UiStrings().ReplaceLiveBG)
|
self.replace_action.setToolTip(UiStrings().ReplaceLiveBG)
|
||||||
self.resetAction.setText(UiStrings().ResetBG)
|
self.reset_action.setText(UiStrings().ResetBG)
|
||||||
self.resetAction.setToolTip(UiStrings().ResetLiveBG)
|
self.reset_action.setToolTip(UiStrings().ResetLiveBG)
|
||||||
self.automatic = UiStrings().Automatic
|
self.automatic = UiStrings().Automatic
|
||||||
self.displayTypeLabel.setText(translate('MediaPlugin.MediaItem', 'Use Player:'))
|
self.display_type_label.setText(translate('MediaPlugin.MediaItem', 'Use Player:'))
|
||||||
self.rebuild_players()
|
self.rebuild_players()
|
||||||
|
|
||||||
def required_icons(self):
|
def required_icons(self):
|
||||||
|
@ -98,27 +101,28 @@ class MediaMediaItem(MediaManagerItem):
|
||||||
|
|
||||||
def add_list_view_to_toolbar(self):
|
def add_list_view_to_toolbar(self):
|
||||||
MediaManagerItem.add_list_view_to_toolbar(self)
|
MediaManagerItem.add_list_view_to_toolbar(self)
|
||||||
self.list_view.addAction(self.replaceAction)
|
self.list_view.addAction(self.replace_action)
|
||||||
|
|
||||||
def add_end_header_bar(self):
|
def add_end_header_bar(self):
|
||||||
# Replace backgrounds do not work at present so remove functionality.
|
# Replace backgrounds do not work at present so remove functionality.
|
||||||
self.replaceAction = self.toolbar.add_toolbar_action(u'replaceAction', icon=u':/slides/slide_blank.png',
|
self.replace_action = self.toolbar.add_toolbar_action(u'replace_action', icon=u':/slides/slide_blank.png',
|
||||||
triggers=self.onReplaceClick)
|
triggers=self.onReplaceClick)
|
||||||
self.resetAction = self.toolbar.add_toolbar_action(u'resetAction', icon=u':/system/system_close.png',
|
self.reset_action = self.toolbar.add_toolbar_action(u'reset_action', icon=u':/system/system_close.png',
|
||||||
visible=False, triggers=self.onResetClick)
|
visible=False, triggers=self.onResetClick)
|
||||||
self.mediaWidget = QtGui.QWidget(self)
|
self.media_widget = QtGui.QWidget(self)
|
||||||
self.mediaWidget.setObjectName(u'mediaWidget')
|
self.media_widget.setObjectName(u'media_widget')
|
||||||
self.displayLayout = QtGui.QFormLayout(self.mediaWidget)
|
self.display_layout = QtGui.QFormLayout(self.media_widget)
|
||||||
self.displayLayout.setMargin(self.displayLayout.spacing())
|
self.display_layout.setMargin(self.display_layout.spacing())
|
||||||
self.displayLayout.setObjectName(u'displayLayout')
|
self.display_layout.setObjectName(u'display_layout')
|
||||||
self.displayTypeLabel = QtGui.QLabel(self.mediaWidget)
|
self.display_type_label = QtGui.QLabel(self.media_widget)
|
||||||
self.displayTypeLabel.setObjectName(u'displayTypeLabel')
|
self.display_type_label.setObjectName(u'display_type_label')
|
||||||
self.displayTypeComboBox = create_horizontal_adjusting_combo_box(self.mediaWidget, u'displayTypeComboBox')
|
self.display_type_combo_box = create_horizontal_adjusting_combo_box(
|
||||||
self.displayTypeLabel.setBuddy(self.displayTypeComboBox)
|
self.media_widget, u'display_type_combo_box')
|
||||||
self.displayLayout.addRow(self.displayTypeLabel, self.displayTypeComboBox)
|
self.display_type_label.setBuddy(self.display_type_combo_box)
|
||||||
# Add the Media widget to the page layout
|
self.display_layout.addRow(self.display_type_label, self.display_type_combo_box)
|
||||||
self.page_layout.addWidget(self.mediaWidget)
|
# Add the Media widget to the page layout.
|
||||||
self.displayTypeComboBox.currentIndexChanged.connect(self.overridePlayerChanged)
|
self.page_layout.addWidget(self.media_widget)
|
||||||
|
self.display_type_combo_box.currentIndexChanged.connect(self.overridePlayerChanged)
|
||||||
|
|
||||||
def overridePlayerChanged(self, index):
|
def overridePlayerChanged(self, index):
|
||||||
player = get_media_players()[0]
|
player = get_media_players()[0]
|
||||||
|
@ -132,13 +136,13 @@ class MediaMediaItem(MediaManagerItem):
|
||||||
Called to reset the Live background with the media selected,
|
Called to reset the Live background with the media selected,
|
||||||
"""
|
"""
|
||||||
self.media_controller.media_reset(self.live_controller)
|
self.media_controller.media_reset(self.live_controller)
|
||||||
self.resetAction.setVisible(False)
|
self.reset_action.setVisible(False)
|
||||||
|
|
||||||
def video_background_replaced(self):
|
def video_background_replaced(self):
|
||||||
"""
|
"""
|
||||||
Triggered by main display on change of serviceitem.
|
Triggered by main display on change of serviceitem.
|
||||||
"""
|
"""
|
||||||
self.resetAction.setVisible(False)
|
self.reset_action.setVisible(False)
|
||||||
|
|
||||||
def onReplaceClick(self):
|
def onReplaceClick(self):
|
||||||
"""
|
"""
|
||||||
|
@ -151,11 +155,11 @@ class MediaMediaItem(MediaManagerItem):
|
||||||
if os.path.exists(filename):
|
if os.path.exists(filename):
|
||||||
service_item = ServiceItem()
|
service_item = ServiceItem()
|
||||||
service_item.title = u'webkit'
|
service_item.title = u'webkit'
|
||||||
service_item.shortname = service_item.title
|
service_item.processor = u'webkit'
|
||||||
(path, name) = os.path.split(filename)
|
(path, name) = os.path.split(filename)
|
||||||
service_item.add_from_command(path, name,CLAPPERBOARD)
|
service_item.add_from_command(path, name,CLAPPERBOARD)
|
||||||
if self.media_controller.video(DisplayControllerType.Live, service_item, video_behind_text=True):
|
if self.media_controller.video(DisplayControllerType.Live, service_item, video_behind_text=True):
|
||||||
self.resetAction.setVisible(True)
|
self.reset_action.setVisible(True)
|
||||||
else:
|
else:
|
||||||
critical_error_message_box(UiStrings().LiveBGError,
|
critical_error_message_box(UiStrings().LiveBGError,
|
||||||
translate('MediaPlugin.MediaItem', 'There was no display item to amend.'))
|
translate('MediaPlugin.MediaItem', 'There was no display item to amend.'))
|
||||||
|
@ -164,7 +168,7 @@ class MediaMediaItem(MediaManagerItem):
|
||||||
translate('MediaPlugin.MediaItem',
|
translate('MediaPlugin.MediaItem',
|
||||||
'There was a problem replacing your background, the media file "%s" no longer exists.') % filename)
|
'There was a problem replacing your background, the media file "%s" no longer exists.') % filename)
|
||||||
|
|
||||||
def generate_slide_data(self, service_item, item=None, xmlVersion=False, remote=False,
|
def generate_slide_data(self, service_item, item=None, xml_version=False, remote=False,
|
||||||
context=ServiceItemContext.Live):
|
context=ServiceItemContext.Live):
|
||||||
"""
|
"""
|
||||||
Generate the slide data. Needs to be implemented by the plugin.
|
Generate the slide data. Needs to be implemented by the plugin.
|
||||||
|
@ -181,9 +185,9 @@ class MediaMediaItem(MediaManagerItem):
|
||||||
translate('MediaPlugin.MediaItem', 'Missing Media File'),
|
translate('MediaPlugin.MediaItem', 'Missing Media File'),
|
||||||
translate('MediaPlugin.MediaItem', 'The file %s no longer exists.') % filename)
|
translate('MediaPlugin.MediaItem', 'The file %s no longer exists.') % filename)
|
||||||
return False
|
return False
|
||||||
service_item.title = self.displayTypeComboBox.currentText()
|
|
||||||
service_item.shortname = service_item.title
|
|
||||||
(path, name) = os.path.split(filename)
|
(path, name) = os.path.split(filename)
|
||||||
|
service_item.title = name
|
||||||
|
service_item.processor = self.display_type_combo_box.currentText()
|
||||||
service_item.add_from_command(path, name, CLAPPERBOARD)
|
service_item.add_from_command(path, name, CLAPPERBOARD)
|
||||||
# Only get start and end times if going to a service
|
# Only get start and end times if going to a service
|
||||||
if context == ServiceItemContext.Service:
|
if context == ServiceItemContext.Service:
|
||||||
|
@ -192,7 +196,6 @@ class MediaMediaItem(MediaManagerItem):
|
||||||
return False
|
return False
|
||||||
service_item.add_capability(ItemCapabilities.CanAutoStartForLive)
|
service_item.add_capability(ItemCapabilities.CanAutoStartForLive)
|
||||||
service_item.add_capability(ItemCapabilities.RequiresMedia)
|
service_item.add_capability(ItemCapabilities.RequiresMedia)
|
||||||
service_item.add_capability(ItemCapabilities.HasDetailedTitleDisplay)
|
|
||||||
if Settings().value(self.settings_section + u'/media auto start') == QtCore.Qt.Checked:
|
if Settings().value(self.settings_section + u'/media auto start') == QtCore.Qt.Checked:
|
||||||
service_item.will_auto_start = True
|
service_item.will_auto_start = True
|
||||||
# force a non-existent theme
|
# force a non-existent theme
|
||||||
|
@ -209,8 +212,7 @@ class MediaMediaItem(MediaManagerItem):
|
||||||
|
|
||||||
def rebuild_players(self):
|
def rebuild_players(self):
|
||||||
"""
|
"""
|
||||||
Rebuild the tab in the media manager when changes are made in
|
Rebuild the tab in the media manager when changes are made in the settings.
|
||||||
the settings
|
|
||||||
"""
|
"""
|
||||||
self.populateDisplayTypes()
|
self.populateDisplayTypes()
|
||||||
self.on_new_file_masks = translate('MediaPlugin.MediaItem', 'Videos (%s);;Audio (%s);;%s (*)') % (
|
self.on_new_file_masks = translate('MediaPlugin.MediaItem', 'Videos (%s);;Audio (%s);;%s (*)') % (
|
||||||
|
@ -222,29 +224,27 @@ class MediaMediaItem(MediaManagerItem):
|
||||||
|
|
||||||
def populateDisplayTypes(self):
|
def populateDisplayTypes(self):
|
||||||
"""
|
"""
|
||||||
Load the combobox with the enabled media players,
|
Load the combobox with the enabled media players, allowing user to select a specific player if settings allow.
|
||||||
allowing user to select a specific player if settings allow
|
|
||||||
"""
|
"""
|
||||||
# block signals to avoid unnecessary overridePlayerChanged Signals
|
# block signals to avoid unnecessary overridePlayerChanged Signals while combo box creation
|
||||||
# while combo box creation
|
self.display_type_combo_box.blockSignals(True)
|
||||||
self.displayTypeComboBox.blockSignals(True)
|
self.display_type_combo_box.clear()
|
||||||
self.displayTypeComboBox.clear()
|
|
||||||
usedPlayers, overridePlayer = get_media_players()
|
usedPlayers, overridePlayer = get_media_players()
|
||||||
media_players = self.media_controller.media_players
|
media_players = self.media_controller.media_players
|
||||||
currentIndex = 0
|
currentIndex = 0
|
||||||
for player in usedPlayers:
|
for player in usedPlayers:
|
||||||
# load the drop down selection
|
# load the drop down selection
|
||||||
self.displayTypeComboBox.addItem(media_players[player].original_name)
|
self.display_type_combo_box.addItem(media_players[player].original_name)
|
||||||
if overridePlayer == player:
|
if overridePlayer == player:
|
||||||
currentIndex = len(self.displayTypeComboBox)
|
currentIndex = len(self.display_type_combo_box)
|
||||||
if self.displayTypeComboBox.count() > 1:
|
if self.display_type_combo_box.count() > 1:
|
||||||
self.displayTypeComboBox.insertItem(0, self.automatic)
|
self.display_type_combo_box.insertItem(0, self.automatic)
|
||||||
self.displayTypeComboBox.setCurrentIndex(currentIndex)
|
self.display_type_combo_box.setCurrentIndex(currentIndex)
|
||||||
if overridePlayer:
|
if overridePlayer:
|
||||||
self.mediaWidget.show()
|
self.media_widget.show()
|
||||||
else:
|
else:
|
||||||
self.mediaWidget.hide()
|
self.media_widget.hide()
|
||||||
self.displayTypeComboBox.blockSignals(False)
|
self.display_type_combo_box.blockSignals(False)
|
||||||
|
|
||||||
def on_delete_click(self):
|
def on_delete_click(self):
|
||||||
"""
|
"""
|
||||||
|
@ -259,42 +259,41 @@ class MediaMediaItem(MediaManagerItem):
|
||||||
Settings().setValue(self.settings_section + u'/media files', self.get_file_list())
|
Settings().setValue(self.settings_section + u'/media files', self.get_file_list())
|
||||||
|
|
||||||
def load_list(self, media, target_group=None):
|
def load_list(self, media, target_group=None):
|
||||||
# Sort the media by its filename considering language specific
|
# Sort the media by its filename considering language specific characters.
|
||||||
# characters.
|
|
||||||
media.sort(key=lambda filename: get_locale_key(os.path.split(unicode(filename))[1]))
|
media.sort(key=lambda filename: get_locale_key(os.path.split(unicode(filename))[1]))
|
||||||
for track in media:
|
for track in media:
|
||||||
track_info = QtCore.QFileInfo(track)
|
track_info = QtCore.QFileInfo(track)
|
||||||
if not os.path.exists(track):
|
if not os.path.exists(track):
|
||||||
filename = os.path.split(unicode(track))[1]
|
filename = os.path.split(unicode(track))[1]
|
||||||
item_name = QtGui.QListWidgetItem(filename)
|
item_name = QtGui.QListWidgetItem(filename)
|
||||||
item_name.setIcon(ERROR)
|
item_name.setIcon(ERROR_ICON)
|
||||||
item_name.setData(QtCore.Qt.UserRole, track)
|
item_name.setData(QtCore.Qt.UserRole, track)
|
||||||
elif track_info.isFile():
|
elif track_info.isFile():
|
||||||
filename = os.path.split(unicode(track))[1]
|
filename = os.path.split(unicode(track))[1]
|
||||||
item_name = QtGui.QListWidgetItem(filename)
|
item_name = QtGui.QListWidgetItem(filename)
|
||||||
if u'*.%s' % (filename.split(u'.')[-1].lower()) in self.media_controller.audio_extensions_list:
|
if u'*.%s' % (filename.split(u'.')[-1].lower()) in self.media_controller.audio_extensions_list:
|
||||||
item_name.setIcon(AUDIO)
|
item_name.setIcon(AUDIO_ICON)
|
||||||
else:
|
else:
|
||||||
item_name.setIcon(VIDEO)
|
item_name.setIcon(VIDEO_ICON)
|
||||||
item_name.setData(QtCore.Qt.UserRole, track)
|
item_name.setData(QtCore.Qt.UserRole, track)
|
||||||
else:
|
else:
|
||||||
filename = os.path.split(unicode(track))[1]
|
filename = os.path.split(unicode(track))[1]
|
||||||
item_name = QtGui.QListWidgetItem(filename)
|
item_name = QtGui.QListWidgetItem(filename)
|
||||||
item_name.setIcon(build_icon(DVDICON))
|
item_name.setIcon(build_icon(DVD_ICON))
|
||||||
item_name.setData(QtCore.Qt.UserRole, track)
|
item_name.setData(QtCore.Qt.UserRole, track)
|
||||||
item_name.setToolTip(track)
|
item_name.setToolTip(track)
|
||||||
self.list_view.addItem(item_name)
|
self.list_view.addItem(item_name)
|
||||||
|
|
||||||
def getList(self, type=MediaType.Audio):
|
def get_list(self, type=MediaType.Audio):
|
||||||
media = Settings().value(self.settings_section + u'/media files')
|
media = Settings().value(self.settings_section + u'/media files')
|
||||||
media.sort(key=lambda filename: get_locale_key(os.path.split(unicode(filename))[1]))
|
media.sort(key=lambda filename: get_locale_key(os.path.split(unicode(filename))[1]))
|
||||||
ext = []
|
extension = []
|
||||||
if type == MediaType.Audio:
|
if type == MediaType.Audio:
|
||||||
ext = self.media_controller.audio_extensions_list
|
extension = self.media_controller.audio_extensions_list
|
||||||
else:
|
else:
|
||||||
ext = self.media_controller.video_extensions_list
|
extension = self.media_controller.video_extensions_list
|
||||||
ext = map(lambda x: x[1:], ext)
|
extension = map(lambda x: x[1:], extension)
|
||||||
media = filter(lambda x: os.path.splitext(x)[1] in ext, media)
|
media = filter(lambda x: os.path.splitext(x)[1] in extension, media)
|
||||||
return media
|
return media
|
||||||
|
|
||||||
def search(self, string, showError):
|
def search(self, string, showError):
|
||||||
|
|
|
@ -34,12 +34,14 @@ from PyQt4 import QtCore
|
||||||
from openlp.core.lib import Plugin, Registry, StringContent, Settings, build_icon, translate
|
from openlp.core.lib import Plugin, Registry, StringContent, Settings, build_icon, translate
|
||||||
from openlp.plugins.media.lib import MediaMediaItem, MediaTab
|
from openlp.plugins.media.lib import MediaMediaItem, MediaTab
|
||||||
|
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
# Some settings starting with "media" are in core, because they are needed for core functionality.
|
# Some settings starting with "media" are in core, because they are needed for core functionality.
|
||||||
__default_settings__ = {
|
__default_settings__ = {
|
||||||
u'media/media auto start': QtCore.Qt.Unchecked,
|
u'media/media auto start': QtCore.Qt.Unchecked,
|
||||||
u'media/media files': []
|
u'media/media files': []
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -54,7 +56,7 @@ class MediaPlugin(Plugin):
|
||||||
# passed with drag and drop messages
|
# passed with drag and drop messages
|
||||||
self.dnd_id = u'Media'
|
self.dnd_id = u'Media'
|
||||||
|
|
||||||
def create_settings_Tab(self, parent):
|
def create_settings_tab(self, parent):
|
||||||
"""
|
"""
|
||||||
Create the settings Tab
|
Create the settings Tab
|
||||||
"""
|
"""
|
||||||
|
@ -94,7 +96,7 @@ class MediaPlugin(Plugin):
|
||||||
|
|
||||||
def finalise(self):
|
def finalise(self):
|
||||||
"""
|
"""
|
||||||
Time to tidy up on exit
|
Time to tidy up on exit.
|
||||||
"""
|
"""
|
||||||
log.info(u'Media Finalising')
|
log.info(u'Media Finalising')
|
||||||
self.media_controller.finalise()
|
self.media_controller.finalise()
|
||||||
|
@ -102,19 +104,19 @@ class MediaPlugin(Plugin):
|
||||||
|
|
||||||
def get_display_css(self):
|
def get_display_css(self):
|
||||||
"""
|
"""
|
||||||
Add css style sheets to htmlbuilder
|
Add css style sheets to htmlbuilder.
|
||||||
"""
|
"""
|
||||||
return self.media_controller.get_media_display_css()
|
return self.media_controller.get_media_display_css()
|
||||||
|
|
||||||
def get_display_javascript(self):
|
def get_display_javascript(self):
|
||||||
"""
|
"""
|
||||||
Add javascript functions to htmlbuilder
|
Add javascript functions to htmlbuilder.
|
||||||
"""
|
"""
|
||||||
return self.media_controller.get_media_display_javascript()
|
return self.media_controller.get_media_display_javascript()
|
||||||
|
|
||||||
def get_display_html(self):
|
def get_display_html(self):
|
||||||
"""
|
"""
|
||||||
Add html code to htmlbuilder
|
Add html code to htmlbuilder.
|
||||||
"""
|
"""
|
||||||
return self.media_controller.get_media_display_html()
|
return self.media_controller.get_media_display_html()
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,6 @@
|
||||||
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
||||||
###############################################################################
|
###############################################################################
|
||||||
"""
|
"""
|
||||||
The :mod:`presentations` module provides the Presentations plugin which allows
|
The :mod:`presentations` module provides the Presentations plugin which allows OpenLP to show presentations from most
|
||||||
OpenLP to show presentations from most popular presentation packages.
|
popular presentation packages.
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -62,13 +62,14 @@ from openlp.core.lib import ScreenList
|
||||||
from openlp.core.utils import delete_file, get_uno_command, get_uno_instance
|
from openlp.core.utils import delete_file, get_uno_command, get_uno_instance
|
||||||
from presentationcontroller import PresentationController, PresentationDocument
|
from presentationcontroller import PresentationController, PresentationDocument
|
||||||
|
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class ImpressController(PresentationController):
|
class ImpressController(PresentationController):
|
||||||
"""
|
"""
|
||||||
Class to control interactions with Impress presentations.
|
Class to control interactions with Impress presentations. It creates the runtime environment, loads and closes the
|
||||||
It creates the runtime environment, loads and closes the presentation as
|
presentation as well as triggering the correct activities based on the users input.
|
||||||
well as triggering the correct activities based on the users input
|
|
||||||
"""
|
"""
|
||||||
log.info(u'ImpressController loaded')
|
log.info(u'ImpressController loaded')
|
||||||
|
|
||||||
|
@ -79,14 +80,14 @@ class ImpressController(PresentationController):
|
||||||
log.debug(u'Initialising')
|
log.debug(u'Initialising')
|
||||||
PresentationController.__init__(self, plugin, u'Impress', ImpressDocument)
|
PresentationController.__init__(self, plugin, u'Impress', ImpressDocument)
|
||||||
self.supports = [u'odp']
|
self.supports = [u'odp']
|
||||||
self.alsosupports = [u'ppt', u'pps', u'pptx', u'ppsx']
|
self.also_supports = [u'ppt', u'pps', u'pptx', u'ppsx']
|
||||||
self.process = None
|
self.process = None
|
||||||
self.desktop = None
|
self.desktop = None
|
||||||
self.manager = None
|
self.manager = None
|
||||||
|
|
||||||
def check_available(self):
|
def check_available(self):
|
||||||
"""
|
"""
|
||||||
Impress is able to run on this machine
|
Impress is able to run on this machine.
|
||||||
"""
|
"""
|
||||||
log.debug(u'check_available')
|
log.debug(u'check_available')
|
||||||
if os.name == u'nt':
|
if os.name == u'nt':
|
||||||
|
@ -96,9 +97,8 @@ class ImpressController(PresentationController):
|
||||||
|
|
||||||
def start_process(self):
|
def start_process(self):
|
||||||
"""
|
"""
|
||||||
Loads a running version of OpenOffice in the background.
|
Loads a running version of OpenOffice in the background. It is not displayed to the user but is available to the
|
||||||
It is not displayed to the user but is available to the UNO interface
|
UNO interface when required.
|
||||||
when required.
|
|
||||||
"""
|
"""
|
||||||
log.debug(u'start process Openoffice')
|
log.debug(u'start process Openoffice')
|
||||||
if os.name == u'nt':
|
if os.name == u'nt':
|
||||||
|
@ -113,8 +113,7 @@ class ImpressController(PresentationController):
|
||||||
|
|
||||||
def get_uno_desktop(self):
|
def get_uno_desktop(self):
|
||||||
"""
|
"""
|
||||||
On non-Windows platforms, use Uno. Get the OpenOffice desktop
|
On non-Windows platforms, use Uno. Get the OpenOffice desktop which will be used to manage impress.
|
||||||
which will be used to manage impress
|
|
||||||
"""
|
"""
|
||||||
log.debug(u'get UNO Desktop Openoffice')
|
log.debug(u'get UNO Desktop Openoffice')
|
||||||
uno_instance = None
|
uno_instance = None
|
||||||
|
@ -132,8 +131,7 @@ class ImpressController(PresentationController):
|
||||||
loop += 1
|
loop += 1
|
||||||
try:
|
try:
|
||||||
self.manager = uno_instance.ServiceManager
|
self.manager = uno_instance.ServiceManager
|
||||||
log.debug(u'get UNO Desktop Openoffice - createInstanceWithContext'
|
log.debug(u'get UNO Desktop Openoffice - createInstanceWithContext - Desktop')
|
||||||
u' - Desktop')
|
|
||||||
desktop = self.manager.createInstanceWithContext("com.sun.star.frame.Desktop", uno_instance)
|
desktop = self.manager.createInstanceWithContext("com.sun.star.frame.Desktop", uno_instance)
|
||||||
return desktop
|
return desktop
|
||||||
except:
|
except:
|
||||||
|
@ -142,8 +140,7 @@ class ImpressController(PresentationController):
|
||||||
|
|
||||||
def get_com_desktop(self):
|
def get_com_desktop(self):
|
||||||
"""
|
"""
|
||||||
On Windows platforms, use COM. Return the desktop object which
|
On Windows platforms, use COM. Return the desktop object which will be used to manage Impress.
|
||||||
will be used to manage Impress
|
|
||||||
"""
|
"""
|
||||||
log.debug(u'get COM Desktop OpenOffice')
|
log.debug(u'get COM Desktop OpenOffice')
|
||||||
if not self.manager:
|
if not self.manager:
|
||||||
|
@ -157,7 +154,7 @@ class ImpressController(PresentationController):
|
||||||
|
|
||||||
def get_com_servicemanager(self):
|
def get_com_servicemanager(self):
|
||||||
"""
|
"""
|
||||||
Return the OOo service manager for windows
|
Return the OOo service manager for windows.
|
||||||
"""
|
"""
|
||||||
log.debug(u'get_com_servicemanager openoffice')
|
log.debug(u'get_com_servicemanager openoffice')
|
||||||
try:
|
try:
|
||||||
|
@ -168,7 +165,7 @@ class ImpressController(PresentationController):
|
||||||
|
|
||||||
def kill(self):
|
def kill(self):
|
||||||
"""
|
"""
|
||||||
Called at system exit to clean up any running presentations
|
Called at system exit to clean up any running presentations.
|
||||||
"""
|
"""
|
||||||
log.debug(u'Kill OpenOffice')
|
log.debug(u'Kill OpenOffice')
|
||||||
while self.docs:
|
while self.docs:
|
||||||
|
@ -203,12 +200,12 @@ class ImpressController(PresentationController):
|
||||||
|
|
||||||
class ImpressDocument(PresentationDocument):
|
class ImpressDocument(PresentationDocument):
|
||||||
"""
|
"""
|
||||||
Class which holds information and controls a single presentation
|
Class which holds information and controls a single presentation.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, controller, presentation):
|
def __init__(self, controller, presentation):
|
||||||
"""
|
"""
|
||||||
Constructor, store information about the file and initialise
|
Constructor, store information about the file and initialise.
|
||||||
"""
|
"""
|
||||||
log.debug(u'Init Presentation OpenOffice')
|
log.debug(u'Init Presentation OpenOffice')
|
||||||
PresentationDocument.__init__(self, controller, presentation)
|
PresentationDocument.__init__(self, controller, presentation)
|
||||||
|
@ -218,11 +215,9 @@ class ImpressDocument(PresentationDocument):
|
||||||
|
|
||||||
def load_presentation(self):
|
def load_presentation(self):
|
||||||
"""
|
"""
|
||||||
Called when a presentation is added to the SlideController.
|
Called when a presentation is added to the SlideController. It builds the environment, starts communcations with
|
||||||
It builds the environment, starts communcations with the background
|
the background OpenOffice task started earlier. If OpenOffice is not present is is started. Once the environment
|
||||||
OpenOffice task started earlier. If OpenOffice is not present is is
|
is available the presentation is loaded and started.
|
||||||
started. Once the environment is available the presentation is loaded
|
|
||||||
and started.
|
|
||||||
"""
|
"""
|
||||||
log.debug(u'Load Presentation OpenOffice')
|
log.debug(u'Load Presentation OpenOffice')
|
||||||
if os.name == u'nt':
|
if os.name == u'nt':
|
||||||
|
@ -239,13 +234,12 @@ class ImpressDocument(PresentationDocument):
|
||||||
self.desktop = desktop
|
self.desktop = desktop
|
||||||
properties = []
|
properties = []
|
||||||
if os.name != u'nt':
|
if os.name != u'nt':
|
||||||
# Recent versions of Impress on Windows won't start the presentation
|
# Recent versions of Impress on Windows won't start the presentation if it starts as minimized. It seems OK
|
||||||
# if it starts as minimized. It seems OK on Linux though.
|
# on Linux though.
|
||||||
properties.append(self.create_property(u'Minimized', True))
|
properties.append(self.create_property(u'Minimized', True))
|
||||||
properties = tuple(properties)
|
properties = tuple(properties)
|
||||||
try:
|
try:
|
||||||
self.document = desktop.loadComponentFromURL(url, u'_blank',
|
self.document = desktop.loadComponentFromURL(url, u'_blank', 0, properties)
|
||||||
0, properties)
|
|
||||||
except:
|
except:
|
||||||
log.warn(u'Failed to load presentation %s' % url)
|
log.warn(u'Failed to load presentation %s' % url)
|
||||||
return False
|
return False
|
||||||
|
@ -262,33 +256,33 @@ class ImpressDocument(PresentationDocument):
|
||||||
|
|
||||||
def create_thumbnails(self):
|
def create_thumbnails(self):
|
||||||
"""
|
"""
|
||||||
Create thumbnail images for presentation
|
Create thumbnail images for presentation.
|
||||||
"""
|
"""
|
||||||
log.debug(u'create thumbnails OpenOffice')
|
log.debug(u'create thumbnails OpenOffice')
|
||||||
if self.check_thumbnails():
|
if self.check_thumbnails():
|
||||||
return
|
return
|
||||||
if os.name == u'nt':
|
if os.name == u'nt':
|
||||||
thumbdirurl = u'file:///' + self.get_temp_folder().replace(u'\\', u'/') \
|
thumb_dir_url = u'file:///' + self.get_temp_folder().replace(u'\\', u'/') \
|
||||||
.replace(u':', u'|').replace(u' ', u'%20')
|
.replace(u':', u'|').replace(u' ', u'%20')
|
||||||
else:
|
else:
|
||||||
thumbdirurl = uno.systemPathToFileUrl(self.get_temp_folder())
|
thumb_dir_url = uno.systemPathToFileUrl(self.get_temp_folder())
|
||||||
props = []
|
properties = []
|
||||||
props.append(self.create_property(u'FilterName', u'impress_png_Export'))
|
properties.append(self.create_property(u'FilterName', u'impress_png_Export'))
|
||||||
props = tuple(props)
|
properties = tuple(properties)
|
||||||
doc = self.document
|
doc = self.document
|
||||||
pages = doc.getDrawPages()
|
pages = doc.getDrawPages()
|
||||||
if not pages:
|
if not pages:
|
||||||
return
|
return
|
||||||
if not os.path.isdir(self.get_temp_folder()):
|
if not os.path.isdir(self.get_temp_folder()):
|
||||||
os.makedirs(self.get_temp_folder())
|
os.makedirs(self.get_temp_folder())
|
||||||
for idx in range(pages.getCount()):
|
for index in range(pages.getCount()):
|
||||||
page = pages.getByIndex(idx)
|
page = pages.getByIndex(index)
|
||||||
doc.getCurrentController().setCurrentPage(page)
|
doc.getCurrentController().setCurrentPage(page)
|
||||||
urlpath = u'%s/%s.png' % (thumbdirurl, unicode(idx + 1))
|
url_path = u'%s/%s.png' % (thumb_dir_url, unicode(index + 1))
|
||||||
path = os.path.join(self.get_temp_folder(), unicode(idx + 1) + u'.png')
|
path = os.path.join(self.get_temp_folder(), unicode(index + 1) + u'.png')
|
||||||
try:
|
try:
|
||||||
doc.storeToURL(urlpath, props)
|
doc.storeToURL(url_path, properties)
|
||||||
self.convert_thumbnail(path, idx + 1)
|
self.convert_thumbnail(path, index + 1)
|
||||||
delete_file(path)
|
delete_file(path)
|
||||||
except ErrorCodeIOException, exception:
|
except ErrorCodeIOException, exception:
|
||||||
log.exception(u'ERROR! ErrorCodeIOException %d' % exception.ErrCode)
|
log.exception(u'ERROR! ErrorCodeIOException %d' % exception.ErrCode)
|
||||||
|
@ -297,23 +291,21 @@ class ImpressDocument(PresentationDocument):
|
||||||
|
|
||||||
def create_property(self, name, value):
|
def create_property(self, name, value):
|
||||||
"""
|
"""
|
||||||
Create an OOo style property object which are passed into some
|
Create an OOo style property object which are passed into some Uno methods.
|
||||||
Uno methods
|
|
||||||
"""
|
"""
|
||||||
log.debug(u'create property OpenOffice')
|
log.debug(u'create property OpenOffice')
|
||||||
if os.name == u'nt':
|
if os.name == u'nt':
|
||||||
prop = self.controller.manager.Bridge_GetStruct(u'com.sun.star.beans.PropertyValue')
|
property_object = self.controller.manager.Bridge_GetStruct(u'com.sun.star.beans.PropertyValue')
|
||||||
else:
|
else:
|
||||||
prop = PropertyValue()
|
property_object = PropertyValue()
|
||||||
prop.Name = name
|
property_object.Name = name
|
||||||
prop.Value = value
|
property_object.Value = value
|
||||||
return prop
|
return property_object
|
||||||
|
|
||||||
def close_presentation(self):
|
def close_presentation(self):
|
||||||
"""
|
"""
|
||||||
Close presentation and clean up objects
|
Close presentation and clean up objects. Triggered by new object being added to SlideController or OpenLP being
|
||||||
Triggered by new object being added to SlideController or OpenLP
|
shutdown.
|
||||||
being shutdown
|
|
||||||
"""
|
"""
|
||||||
log.debug(u'close Presentation OpenOffice')
|
log.debug(u'close Presentation OpenOffice')
|
||||||
if self.document:
|
if self.document:
|
||||||
|
@ -329,7 +321,7 @@ class ImpressDocument(PresentationDocument):
|
||||||
|
|
||||||
def is_loaded(self):
|
def is_loaded(self):
|
||||||
"""
|
"""
|
||||||
Returns true if a presentation is loaded
|
Returns true if a presentation is loaded.
|
||||||
"""
|
"""
|
||||||
log.debug(u'is loaded OpenOffice')
|
log.debug(u'is loaded OpenOffice')
|
||||||
if self.presentation is None or self.document is None:
|
if self.presentation is None or self.document is None:
|
||||||
|
@ -346,7 +338,7 @@ class ImpressDocument(PresentationDocument):
|
||||||
|
|
||||||
def is_active(self):
|
def is_active(self):
|
||||||
"""
|
"""
|
||||||
Returns true if a presentation is active and running
|
Returns true if a presentation is active and running.
|
||||||
"""
|
"""
|
||||||
log.debug(u'is active OpenOffice')
|
log.debug(u'is active OpenOffice')
|
||||||
if not self.is_loaded():
|
if not self.is_loaded():
|
||||||
|
@ -355,21 +347,21 @@ class ImpressDocument(PresentationDocument):
|
||||||
|
|
||||||
def unblank_screen(self):
|
def unblank_screen(self):
|
||||||
"""
|
"""
|
||||||
Unblanks the screen
|
Unblanks the screen.
|
||||||
"""
|
"""
|
||||||
log.debug(u'unblank screen OpenOffice')
|
log.debug(u'unblank screen OpenOffice')
|
||||||
return self.control.resume()
|
return self.control.resume()
|
||||||
|
|
||||||
def blank_screen(self):
|
def blank_screen(self):
|
||||||
"""
|
"""
|
||||||
Blanks the screen
|
Blanks the screen.
|
||||||
"""
|
"""
|
||||||
log.debug(u'blank screen OpenOffice')
|
log.debug(u'blank screen OpenOffice')
|
||||||
self.control.blankScreen(0)
|
self.control.blankScreen(0)
|
||||||
|
|
||||||
def is_blank(self):
|
def is_blank(self):
|
||||||
"""
|
"""
|
||||||
Returns true if screen is blank
|
Returns true if screen is blank.
|
||||||
"""
|
"""
|
||||||
log.debug(u'is blank OpenOffice')
|
log.debug(u'is blank OpenOffice')
|
||||||
if self.control and self.control.isRunning():
|
if self.control and self.control.isRunning():
|
||||||
|
@ -379,7 +371,7 @@ class ImpressDocument(PresentationDocument):
|
||||||
|
|
||||||
def stop_presentation(self):
|
def stop_presentation(self):
|
||||||
"""
|
"""
|
||||||
Stop the presentation, remove from screen
|
Stop the presentation, remove from screen.
|
||||||
"""
|
"""
|
||||||
log.debug(u'stop presentation OpenOffice')
|
log.debug(u'stop presentation OpenOffice')
|
||||||
# deactivate should hide the screen according to docs, but doesn't
|
# deactivate should hide the screen according to docs, but doesn't
|
||||||
|
@ -389,18 +381,17 @@ class ImpressDocument(PresentationDocument):
|
||||||
|
|
||||||
def start_presentation(self):
|
def start_presentation(self):
|
||||||
"""
|
"""
|
||||||
Start the presentation from the beginning
|
Start the presentation from the beginning.
|
||||||
"""
|
"""
|
||||||
log.debug(u'start presentation OpenOffice')
|
log.debug(u'start presentation OpenOffice')
|
||||||
if self.control is None or not self.control.isRunning():
|
if self.control is None or not self.control.isRunning():
|
||||||
self.presentation.start()
|
self.presentation.start()
|
||||||
self.control = self.presentation.getController()
|
self.control = self.presentation.getController()
|
||||||
# start() returns before the Component is ready.
|
# start() returns before the Component is ready. Try for 15 seconds.
|
||||||
# Try for 15 seconds
|
sleep_count = 1
|
||||||
i = 1
|
while not self.control and sleep_count < 150:
|
||||||
while not self.control and i < 150:
|
|
||||||
time.sleep(0.1)
|
time.sleep(0.1)
|
||||||
i += 1
|
sleep_count += 1
|
||||||
self.control = self.presentation.getController()
|
self.control = self.presentation.getController()
|
||||||
else:
|
else:
|
||||||
self.control.activate()
|
self.control.activate()
|
||||||
|
@ -408,25 +399,25 @@ class ImpressDocument(PresentationDocument):
|
||||||
|
|
||||||
def get_slide_number(self):
|
def get_slide_number(self):
|
||||||
"""
|
"""
|
||||||
Return the current slide number on the screen, from 1
|
Return the current slide number on the screen, from 1.
|
||||||
"""
|
"""
|
||||||
return self.control.getCurrentSlideIndex() + 1
|
return self.control.getCurrentSlideIndex() + 1
|
||||||
|
|
||||||
def get_slide_count(self):
|
def get_slide_count(self):
|
||||||
"""
|
"""
|
||||||
Return the total number of slides
|
Return the total number of slides.
|
||||||
"""
|
"""
|
||||||
return self.document.getDrawPages().getCount()
|
return self.document.getDrawPages().getCount()
|
||||||
|
|
||||||
def goto_slide(self, slideno):
|
def goto_slide(self, slideno):
|
||||||
"""
|
"""
|
||||||
Go to a specific slide (from 1)
|
Go to a specific slide (from 1).
|
||||||
"""
|
"""
|
||||||
self.control.gotoSlideIndex(slideno-1)
|
self.control.gotoSlideIndex(slideno-1)
|
||||||
|
|
||||||
def next_step(self):
|
def next_step(self):
|
||||||
"""
|
"""
|
||||||
Triggers the next effect of slide on the running presentation
|
Triggers the next effect of slide on the running presentation.
|
||||||
"""
|
"""
|
||||||
is_paused = self.control.isPaused()
|
is_paused = self.control.isPaused()
|
||||||
self.control.gotoNextEffect()
|
self.control.gotoNextEffect()
|
||||||
|
@ -436,7 +427,7 @@ class ImpressDocument(PresentationDocument):
|
||||||
|
|
||||||
def previous_step(self):
|
def previous_step(self):
|
||||||
"""
|
"""
|
||||||
Triggers the previous slide on the running presentation
|
Triggers the previous slide on the running presentation.
|
||||||
"""
|
"""
|
||||||
self.control.gotoPreviousSlide()
|
self.control.gotoPreviousSlide()
|
||||||
|
|
||||||
|
@ -470,8 +461,8 @@ class ImpressDocument(PresentationDocument):
|
||||||
page = pages.getByIndex(slide_no - 1)
|
page = pages.getByIndex(slide_no - 1)
|
||||||
if notes:
|
if notes:
|
||||||
page = page.getNotesPage()
|
page = page.getNotesPage()
|
||||||
for idx in range(page.getCount()):
|
for index in range(page.getCount()):
|
||||||
shape = page.getByIndex(idx)
|
shape = page.getByIndex(index)
|
||||||
if shape.supportsService("com.sun.star.drawing.Text"):
|
if shape.supportsService("com.sun.star.drawing.Text"):
|
||||||
text += shape.getString() + '\n'
|
text += shape.getString() + '\n'
|
||||||
return text
|
return text
|
||||||
|
|
|
@ -38,14 +38,17 @@ from openlp.core.lib.ui import critical_error_message_box, create_horizontal_adj
|
||||||
from openlp.core.utils import get_locale_key
|
from openlp.core.utils import get_locale_key
|
||||||
from openlp.plugins.presentations.lib import MessageListener
|
from openlp.plugins.presentations.lib import MessageListener
|
||||||
|
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
ERROR = QtGui.QImage(u':/general/general_delete.png')
|
|
||||||
|
ERROR_IMAGE = QtGui.QImage(u':/general/general_delete.png')
|
||||||
|
|
||||||
|
|
||||||
class PresentationMediaItem(MediaManagerItem):
|
class PresentationMediaItem(MediaManagerItem):
|
||||||
"""
|
"""
|
||||||
This is the Presentation media manager item for Presentation Items.
|
This is the Presentation media manager item for Presentation Items. It can present files using Openoffice and
|
||||||
It can present files using Openoffice and Powerpoint
|
Powerpoint
|
||||||
"""
|
"""
|
||||||
log.info(u'Presentations Media Item loaded')
|
log.info(u'Presentations Media Item loaded')
|
||||||
|
|
||||||
|
@ -71,25 +74,25 @@ class PresentationMediaItem(MediaManagerItem):
|
||||||
"""
|
"""
|
||||||
self.on_new_prompt = translate('PresentationPlugin.MediaItem', 'Select Presentation(s)')
|
self.on_new_prompt = translate('PresentationPlugin.MediaItem', 'Select Presentation(s)')
|
||||||
self.Automatic = translate('PresentationPlugin.MediaItem', 'Automatic')
|
self.Automatic = translate('PresentationPlugin.MediaItem', 'Automatic')
|
||||||
self.displayTypeLabel.setText(translate('PresentationPlugin.MediaItem', 'Present using:'))
|
self.display_type_label.setText(translate('PresentationPlugin.MediaItem', 'Present using:'))
|
||||||
|
|
||||||
def build_file_mask_string(self):
|
def build_file_mask_string(self):
|
||||||
"""
|
"""
|
||||||
Build the list of file extensions to be used in the Open file dialog
|
Build the list of file extensions to be used in the Open file dialog.
|
||||||
"""
|
"""
|
||||||
fileType = u''
|
file_type = u''
|
||||||
for controller in self.controllers:
|
for controller in self.controllers:
|
||||||
if self.controllers[controller].enabled():
|
if self.controllers[controller].enabled():
|
||||||
types = self.controllers[controller].supports + self.controllers[controller].alsosupports
|
file_types = self.controllers[controller].supports + self.controllers[controller].also_supports
|
||||||
for type in types:
|
for file_type in file_types:
|
||||||
if fileType.find(type) == -1:
|
if file_type.find(file_type) == -1:
|
||||||
fileType += u'*.%s ' % type
|
file_type += u'*.%s ' % file_type
|
||||||
self.service_manager.supported_suffixes(type)
|
self.service_manager.supported_suffixes(file_type)
|
||||||
self.on_new_file_masks = translate('PresentationPlugin.MediaItem', 'Presentations (%s)') % fileType
|
self.on_new_file_masks = translate('PresentationPlugin.MediaItem', 'Presentations (%s)') % file_type
|
||||||
|
|
||||||
def required_icons(self):
|
def required_icons(self):
|
||||||
"""
|
"""
|
||||||
Set which icons the media manager tab should show
|
Set which icons the media manager tab should show.
|
||||||
"""
|
"""
|
||||||
MediaManagerItem.required_icons(self)
|
MediaManagerItem.required_icons(self)
|
||||||
self.has_file_icon = True
|
self.has_file_icon = True
|
||||||
|
@ -98,21 +101,21 @@ class PresentationMediaItem(MediaManagerItem):
|
||||||
|
|
||||||
def add_end_header_bar(self):
|
def add_end_header_bar(self):
|
||||||
"""
|
"""
|
||||||
Display custom media manager items for presentations
|
Display custom media manager items for presentations.
|
||||||
"""
|
"""
|
||||||
self.presentationWidget = QtGui.QWidget(self)
|
self.presentation_widget = QtGui.QWidget(self)
|
||||||
self.presentationWidget.setObjectName(u'presentationWidget')
|
self.presentation_widget.setObjectName(u'presentation_widget')
|
||||||
self.displayLayout = QtGui.QFormLayout(self.presentationWidget)
|
self.display_layout = QtGui.QFormLayout(self.presentation_widget)
|
||||||
self.displayLayout.setMargin(self.displayLayout.spacing())
|
self.display_layout.setMargin(self.display_layout.spacing())
|
||||||
self.displayLayout.setObjectName(u'displayLayout')
|
self.display_layout.setObjectName(u'display_layout')
|
||||||
self.displayTypeLabel = QtGui.QLabel(self.presentationWidget)
|
self.display_type_label = QtGui.QLabel(self.presentation_widget)
|
||||||
self.displayTypeLabel.setObjectName(u'displayTypeLabel')
|
self.display_type_label.setObjectName(u'display_type_label')
|
||||||
self.displayTypeComboBox = create_horizontal_adjusting_combo_box(self.presentationWidget,
|
self.display_type_combo_box = create_horizontal_adjusting_combo_box(self.presentation_widget,
|
||||||
u'displayTypeComboBox')
|
u'display_type_combo_box')
|
||||||
self.displayTypeLabel.setBuddy(self.displayTypeComboBox)
|
self.display_type_label.setBuddy(self.display_type_combo_box)
|
||||||
self.displayLayout.addRow(self.displayTypeLabel, self.displayTypeComboBox)
|
self.display_layout.addRow(self.display_type_label, self.display_type_combo_box)
|
||||||
# Add the Presentation widget to the page layout
|
# Add the Presentation widget to the page layout.
|
||||||
self.page_layout.addWidget(self.presentationWidget)
|
self.page_layout.addWidget(self.presentation_widget)
|
||||||
|
|
||||||
def initialise(self):
|
def initialise(self):
|
||||||
"""
|
"""
|
||||||
|
@ -120,55 +123,54 @@ class PresentationMediaItem(MediaManagerItem):
|
||||||
"""
|
"""
|
||||||
self.list_view.setIconSize(QtCore.QSize(88, 50))
|
self.list_view.setIconSize(QtCore.QSize(88, 50))
|
||||||
files = Settings().value(self.settings_section + u'/presentations files')
|
files = Settings().value(self.settings_section + u'/presentations files')
|
||||||
self.load_list(files, initialLoad=True)
|
self.load_list(files, initial_load=True)
|
||||||
self.populate_display_types()
|
self.populate_display_types()
|
||||||
|
|
||||||
def populate_display_types(self):
|
def populate_display_types(self):
|
||||||
"""
|
"""
|
||||||
Load the combobox with the enabled presentation controllers,
|
Load the combobox with the enabled presentation controllers, allowing user to select a specific app if settings
|
||||||
allowing user to select a specific app if settings allow
|
allow.
|
||||||
"""
|
"""
|
||||||
self.displayTypeComboBox.clear()
|
self.display_type_combo_box.clear()
|
||||||
for item in self.controllers:
|
for item in self.controllers:
|
||||||
# load the drop down selection
|
# load the drop down selection
|
||||||
if self.controllers[item].enabled():
|
if self.controllers[item].enabled():
|
||||||
self.displayTypeComboBox.addItem(item)
|
self.display_type_combo_box.addItem(item)
|
||||||
if self.displayTypeComboBox.count() > 1:
|
if self.display_type_combo_box.count() > 1:
|
||||||
self.displayTypeComboBox.insertItem(0, self.Automatic)
|
self.display_type_combo_box.insertItem(0, self.Automatic)
|
||||||
self.displayTypeComboBox.setCurrentIndex(0)
|
self.display_type_combo_box.setCurrentIndex(0)
|
||||||
if Settings().value(self.settings_section + u'/override app') == QtCore.Qt.Checked:
|
if Settings().value(self.settings_section + u'/override app') == QtCore.Qt.Checked:
|
||||||
self.presentationWidget.show()
|
self.presentation_widget.show()
|
||||||
else:
|
else:
|
||||||
self.presentationWidget.hide()
|
self.presentation_widget.hide()
|
||||||
|
|
||||||
def load_list(self, files, target_group=None, initialLoad=False):
|
def load_list(self, files, target_group=None, initial_load=False):
|
||||||
"""
|
"""
|
||||||
Add presentations into the media manager
|
Add presentations into the media manager. This is called both on initial load of the plugin to populate with
|
||||||
This is called both on initial load of the plugin to populate with
|
existing files, and when the user adds new files via the media manager.
|
||||||
existing files, and when the user adds new files via the media manager
|
|
||||||
"""
|
"""
|
||||||
currlist = self.get_file_list()
|
current_list = self.get_file_list()
|
||||||
titles = [os.path.split(file)[1] for file in currlist]
|
titles = [os.path.split(file)[1] for file in current_list]
|
||||||
self.application.set_busy_cursor()
|
self.application.set_busy_cursor()
|
||||||
if not initialLoad:
|
if not initial_load:
|
||||||
self.main_window.display_progress_bar(len(files))
|
self.main_window.display_progress_bar(len(files))
|
||||||
# Sort the presentations by its filename considering language specific characters.
|
# Sort the presentations by its filename considering language specific characters.
|
||||||
files.sort(key=lambda filename: get_locale_key(os.path.split(unicode(filename))[1]))
|
files.sort(key=lambda filename: get_locale_key(os.path.split(unicode(filename))[1]))
|
||||||
for file in files:
|
for file in files:
|
||||||
if not initialLoad:
|
if not initial_load:
|
||||||
self.main_window.increment_progress_bar()
|
self.main_window.increment_progress_bar()
|
||||||
if currlist.count(file) > 0:
|
if current_list.count(file) > 0:
|
||||||
continue
|
continue
|
||||||
filename = os.path.split(unicode(file))[1]
|
filename = os.path.split(unicode(file))[1]
|
||||||
if not os.path.exists(file):
|
if not os.path.exists(file):
|
||||||
item_name = QtGui.QListWidgetItem(filename)
|
item_name = QtGui.QListWidgetItem(filename)
|
||||||
item_name.setIcon(build_icon(ERROR))
|
item_name.setIcon(build_icon(ERROR_IMAGE))
|
||||||
item_name.setData(QtCore.Qt.UserRole, file)
|
item_name.setData(QtCore.Qt.UserRole, file)
|
||||||
item_name.setToolTip(file)
|
item_name.setToolTip(file)
|
||||||
self.list_view.addItem(item_name)
|
self.list_view.addItem(item_name)
|
||||||
else:
|
else:
|
||||||
if titles.count(filename) > 0:
|
if titles.count(filename) > 0:
|
||||||
if not initialLoad:
|
if not initial_load:
|
||||||
critical_error_message_box(translate('PresentationPlugin.MediaItem', 'File Exists'),
|
critical_error_message_box(translate('PresentationPlugin.MediaItem', 'File Exists'),
|
||||||
translate('PresentationPlugin.MediaItem',
|
translate('PresentationPlugin.MediaItem',
|
||||||
'A presentation with that filename already exists.')
|
'A presentation with that filename already exists.')
|
||||||
|
@ -180,7 +182,7 @@ class PresentationMediaItem(MediaManagerItem):
|
||||||
doc = controller.add_document(unicode(file))
|
doc = controller.add_document(unicode(file))
|
||||||
thumb = os.path.join(doc.get_thumbnail_folder(), u'icon.png')
|
thumb = os.path.join(doc.get_thumbnail_folder(), u'icon.png')
|
||||||
preview = doc.get_thumbnail_path(1, True)
|
preview = doc.get_thumbnail_path(1, True)
|
||||||
if not preview and not initialLoad:
|
if not preview and not initial_load:
|
||||||
doc.load_presentation()
|
doc.load_presentation()
|
||||||
preview = doc.get_thumbnail_path(1, True)
|
preview = doc.get_thumbnail_path(1, True)
|
||||||
doc.close_presentation()
|
doc.close_presentation()
|
||||||
|
@ -192,7 +194,7 @@ class PresentationMediaItem(MediaManagerItem):
|
||||||
else:
|
else:
|
||||||
icon = create_thumb(preview, thumb)
|
icon = create_thumb(preview, thumb)
|
||||||
else:
|
else:
|
||||||
if initialLoad:
|
if initial_load:
|
||||||
icon = build_icon(u':/general/general_delete.png')
|
icon = build_icon(u':/general/general_delete.png')
|
||||||
else:
|
else:
|
||||||
critical_error_message_box(UiStrings().UnsupportedFile,
|
critical_error_message_box(UiStrings().UnsupportedFile,
|
||||||
|
@ -203,13 +205,13 @@ class PresentationMediaItem(MediaManagerItem):
|
||||||
item_name.setIcon(icon)
|
item_name.setIcon(icon)
|
||||||
item_name.setToolTip(file)
|
item_name.setToolTip(file)
|
||||||
self.list_view.addItem(item_name)
|
self.list_view.addItem(item_name)
|
||||||
if not initialLoad:
|
if not initial_load:
|
||||||
self.main_window.finished_progress_bar()
|
self.main_window.finished_progress_bar()
|
||||||
self.application.set_normal_cursor()
|
self.application.set_normal_cursor()
|
||||||
|
|
||||||
def on_delete_click(self):
|
def on_delete_click(self):
|
||||||
"""
|
"""
|
||||||
Remove a presentation item from the list
|
Remove a presentation item from the list.
|
||||||
"""
|
"""
|
||||||
if check_item_selected(self.list_view, UiStrings().SelectDelete):
|
if check_item_selected(self.list_view, UiStrings().SelectDelete):
|
||||||
items = self.list_view.selectedIndexes()
|
items = self.list_view.selectedIndexes()
|
||||||
|
@ -230,12 +232,11 @@ class PresentationMediaItem(MediaManagerItem):
|
||||||
self.list_view.takeItem(row)
|
self.list_view.takeItem(row)
|
||||||
Settings().setValue(self.settings_section + u'/presentations files', self.get_file_list())
|
Settings().setValue(self.settings_section + u'/presentations files', self.get_file_list())
|
||||||
|
|
||||||
def generate_slide_data(self, service_item, item=None, xmlVersion=False,
|
def generate_slide_data(self, service_item, item=None, xml_version=False,
|
||||||
remote=False, context=ServiceItemContext.Service):
|
remote=False, context=ServiceItemContext.Service):
|
||||||
"""
|
"""
|
||||||
Load the relevant information for displaying the presentation
|
Load the relevant information for displaying the presentation in the slidecontroller. In the case of
|
||||||
in the slidecontroller. In the case of powerpoints, an image
|
powerpoints, an image for each slide.
|
||||||
for each slide
|
|
||||||
"""
|
"""
|
||||||
if item:
|
if item:
|
||||||
items = [item]
|
items = [item]
|
||||||
|
@ -243,22 +244,20 @@ class PresentationMediaItem(MediaManagerItem):
|
||||||
items = self.list_view.selectedItems()
|
items = self.list_view.selectedItems()
|
||||||
if len(items) > 1:
|
if len(items) > 1:
|
||||||
return False
|
return False
|
||||||
service_item.title = self.displayTypeComboBox.currentText()
|
service_item.processor = self.display_type_combo_box.currentText()
|
||||||
service_item.shortname = self.displayTypeComboBox.currentText()
|
|
||||||
service_item.add_capability(ItemCapabilities.ProvidesOwnDisplay)
|
service_item.add_capability(ItemCapabilities.ProvidesOwnDisplay)
|
||||||
service_item.add_capability(ItemCapabilities.HasDetailedTitleDisplay)
|
if not self.display_type_combo_box.currentText():
|
||||||
shortname = service_item.shortname
|
|
||||||
if not shortname:
|
|
||||||
return False
|
return False
|
||||||
for bitem in items:
|
for bitem in items:
|
||||||
filename = bitem.data(QtCore.Qt.UserRole)
|
filename = bitem.data(QtCore.Qt.UserRole)
|
||||||
|
(path, name) = os.path.split(filename)
|
||||||
|
service_item.title = name
|
||||||
if os.path.exists(filename):
|
if os.path.exists(filename):
|
||||||
if shortname == self.Automatic:
|
if service_item.processor == self.Automatic:
|
||||||
service_item.shortname = self.findControllerByType(filename)
|
service_item.processor = self.findControllerByType(filename)
|
||||||
if not service_item.shortname:
|
if not service_item.processor:
|
||||||
return False
|
return False
|
||||||
controller = self.controllers[service_item.shortname]
|
controller = self.controllers[service_item.processor]
|
||||||
(path, name) = os.path.split(filename)
|
|
||||||
doc = controller.add_document(filename)
|
doc = controller.add_document(filename)
|
||||||
if doc.get_thumbnail_path(1, True) is None:
|
if doc.get_thumbnail_path(1, True) is None:
|
||||||
doc.load_presentation()
|
doc.load_presentation()
|
||||||
|
@ -287,26 +286,24 @@ class PresentationMediaItem(MediaManagerItem):
|
||||||
|
|
||||||
def findControllerByType(self, filename):
|
def findControllerByType(self, filename):
|
||||||
"""
|
"""
|
||||||
Determine the default application controller to use for the selected
|
Determine the default application controller to use for the selected file type. This is used if "Automatic" is
|
||||||
file type. This is used if "Automatic" is set as the preferred
|
set as the preferred controller. Find the first (alphabetic) enabled controller which "supports" the extension.
|
||||||
controller. Find the first (alphabetic) enabled controller which
|
If none found, then look for a controller which "also supports" it instead.
|
||||||
"supports" the extension. If none found, then look for a controller
|
|
||||||
which "also supports" it instead.
|
|
||||||
"""
|
"""
|
||||||
filetype = os.path.splitext(filename)[1][1:]
|
file_type = os.path.splitext(filename)[1][1:]
|
||||||
if not filetype:
|
if not file_type:
|
||||||
return None
|
return None
|
||||||
for controller in self.controllers:
|
for controller in self.controllers:
|
||||||
if self.controllers[controller].enabled():
|
if self.controllers[controller].enabled():
|
||||||
if filetype in self.controllers[controller].supports:
|
if file_type in self.controllers[controller].supports:
|
||||||
return controller
|
return controller
|
||||||
for controller in self.controllers:
|
for controller in self.controllers:
|
||||||
if self.controllers[controller].enabled():
|
if self.controllers[controller].enabled():
|
||||||
if filetype in self.controllers[controller].alsosupports:
|
if file_type in self.controllers[controller].also_supports:
|
||||||
return controller
|
return controller
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def search(self, string, showError):
|
def search(self, string, show_error):
|
||||||
files = Settings().value(self.settings_section + u'/presentations files')
|
files = Settings().value(self.settings_section + u'/presentations files')
|
||||||
results = []
|
results = []
|
||||||
string = string.lower()
|
string = string.lower()
|
||||||
|
|
|
@ -36,10 +36,11 @@ from openlp.core.ui import HideMode
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class Controller(object):
|
class Controller(object):
|
||||||
"""
|
"""
|
||||||
This is the Presentation listener who acts on events from the slide
|
This is the Presentation listener who acts on events from the slide controller and passes the messages on the the
|
||||||
controller and passes the messages on the the correct presentation handlers
|
correct presentation handlers.
|
||||||
"""
|
"""
|
||||||
log.info(u'Controller loaded')
|
log.info(u'Controller loaded')
|
||||||
|
|
||||||
|
@ -54,9 +55,8 @@ class Controller(object):
|
||||||
|
|
||||||
def add_handler(self, controller, file, hide_mode, slide_no):
|
def add_handler(self, controller, file, hide_mode, slide_no):
|
||||||
"""
|
"""
|
||||||
Add a handler, which is an instance of a presentation and
|
Add a handler, which is an instance of a presentation and slidecontroller combination. If the slidecontroller
|
||||||
slidecontroller combination. If the slidecontroller has a display
|
has a display then load the presentation.
|
||||||
then load the presentation.
|
|
||||||
"""
|
"""
|
||||||
log.debug(u'Live = %s, add_handler %s' % (self.is_live, file))
|
log.debug(u'Live = %s, add_handler %s' % (self.is_live, file))
|
||||||
self.controller = controller
|
self.controller = controller
|
||||||
|
@ -86,8 +86,7 @@ class Controller(object):
|
||||||
|
|
||||||
def activate(self):
|
def activate(self):
|
||||||
"""
|
"""
|
||||||
Active the presentation, and show it on the screen.
|
Active the presentation, and show it on the screen. Use the last slide number.
|
||||||
Use the last slide number.
|
|
||||||
"""
|
"""
|
||||||
log.debug(u'Live = %s, activate' % self.is_live)
|
log.debug(u'Live = %s, activate' % self.is_live)
|
||||||
if not self.doc:
|
if not self.doc:
|
||||||
|
@ -130,7 +129,7 @@ class Controller(object):
|
||||||
|
|
||||||
def first(self):
|
def first(self):
|
||||||
"""
|
"""
|
||||||
Based on the handler passed at startup triggers the first slide
|
Based on the handler passed at startup triggers the first slide.
|
||||||
"""
|
"""
|
||||||
log.debug(u'Live = %s, first' % self.is_live)
|
log.debug(u'Live = %s, first' % self.is_live)
|
||||||
if not self.doc:
|
if not self.doc:
|
||||||
|
@ -148,7 +147,7 @@ class Controller(object):
|
||||||
|
|
||||||
def last(self):
|
def last(self):
|
||||||
"""
|
"""
|
||||||
Based on the handler passed at startup triggers the last slide
|
Based on the handler passed at startup triggers the last slide.
|
||||||
"""
|
"""
|
||||||
log.debug(u'Live = %s, last' % self.is_live)
|
log.debug(u'Live = %s, last' % self.is_live)
|
||||||
if not self.doc:
|
if not self.doc:
|
||||||
|
@ -166,7 +165,7 @@ class Controller(object):
|
||||||
|
|
||||||
def next(self):
|
def next(self):
|
||||||
"""
|
"""
|
||||||
Based on the handler passed at startup triggers the next slide event
|
Based on the handler passed at startup triggers the next slide event.
|
||||||
"""
|
"""
|
||||||
log.debug(u'Live = %s, next' % self.is_live)
|
log.debug(u'Live = %s, next' % self.is_live)
|
||||||
if not self.doc:
|
if not self.doc:
|
||||||
|
@ -182,9 +181,8 @@ class Controller(object):
|
||||||
return
|
return
|
||||||
if not self.activate():
|
if not self.activate():
|
||||||
return
|
return
|
||||||
# The "End of slideshow" screen is after the last slide
|
# The "End of slideshow" screen is after the last slide. Note, we can't just stop on the last slide, since it
|
||||||
# Note, we can't just stop on the last slide, since it may
|
# may contain animations that need to be stepped through.
|
||||||
# contain animations that need to be stepped through.
|
|
||||||
if self.doc.slidenumber > self.doc.get_slide_count():
|
if self.doc.slidenumber > self.doc.get_slide_count():
|
||||||
return
|
return
|
||||||
self.doc.next_step()
|
self.doc.next_step()
|
||||||
|
@ -192,7 +190,7 @@ class Controller(object):
|
||||||
|
|
||||||
def previous(self):
|
def previous(self):
|
||||||
"""
|
"""
|
||||||
Based on the handler passed at startup triggers the previous slide event
|
Based on the handler passed at startup triggers the previous slide event.
|
||||||
"""
|
"""
|
||||||
log.debug(u'Live = %s, previous' % self.is_live)
|
log.debug(u'Live = %s, previous' % self.is_live)
|
||||||
if not self.doc:
|
if not self.doc:
|
||||||
|
@ -213,7 +211,7 @@ class Controller(object):
|
||||||
|
|
||||||
def shutdown(self):
|
def shutdown(self):
|
||||||
"""
|
"""
|
||||||
Based on the handler passed at startup triggers slide show to shut down
|
Based on the handler passed at startup triggers slide show to shut down.
|
||||||
"""
|
"""
|
||||||
log.debug(u'Live = %s, shutdown' % self.is_live)
|
log.debug(u'Live = %s, shutdown' % self.is_live)
|
||||||
if not self.doc:
|
if not self.doc:
|
||||||
|
@ -223,7 +221,7 @@ class Controller(object):
|
||||||
|
|
||||||
def blank(self, hide_mode):
|
def blank(self, hide_mode):
|
||||||
"""
|
"""
|
||||||
Instruct the controller to blank the presentation
|
Instruct the controller to blank the presentation.
|
||||||
"""
|
"""
|
||||||
log.debug(u'Live = %s, blank' % self.is_live)
|
log.debug(u'Live = %s, blank' % self.is_live)
|
||||||
self.hide_mode = hide_mode
|
self.hide_mode = hide_mode
|
||||||
|
@ -244,7 +242,7 @@ class Controller(object):
|
||||||
|
|
||||||
def stop(self):
|
def stop(self):
|
||||||
"""
|
"""
|
||||||
Instruct the controller to stop and hide the presentation
|
Instruct the controller to stop and hide the presentation.
|
||||||
"""
|
"""
|
||||||
log.debug(u'Live = %s, stop' % self.is_live)
|
log.debug(u'Live = %s, stop' % self.is_live)
|
||||||
self.hide_mode = HideMode.Screen
|
self.hide_mode = HideMode.Screen
|
||||||
|
@ -260,7 +258,7 @@ class Controller(object):
|
||||||
|
|
||||||
def unblank(self):
|
def unblank(self):
|
||||||
"""
|
"""
|
||||||
Instruct the controller to unblank the presentation
|
Instruct the controller to unblank the presentation.
|
||||||
"""
|
"""
|
||||||
log.debug(u'Live = %s, unblank' % self.is_live)
|
log.debug(u'Live = %s, unblank' % self.is_live)
|
||||||
self.hide_mode = None
|
self.hide_mode = None
|
||||||
|
@ -283,8 +281,8 @@ class Controller(object):
|
||||||
|
|
||||||
class MessageListener(object):
|
class MessageListener(object):
|
||||||
"""
|
"""
|
||||||
This is the Presentation listener who acts on events from the slide
|
This is the Presentation listener who acts on events from the slide controller and passes the messages on the the
|
||||||
controller and passes the messages on the the correct presentation handlers
|
correct presentation handlers
|
||||||
"""
|
"""
|
||||||
log.info(u'Message Listener loaded')
|
log.info(u'Message Listener loaded')
|
||||||
|
|
||||||
|
@ -310,15 +308,14 @@ class MessageListener(object):
|
||||||
|
|
||||||
def startup(self, message):
|
def startup(self, message):
|
||||||
"""
|
"""
|
||||||
Start of new presentation
|
Start of new presentation. Save the handler as any new presentations start here
|
||||||
Save the handler as any new presentations start here
|
|
||||||
"""
|
"""
|
||||||
|
log.debug(u'Startup called with message %s' % message)
|
||||||
is_live = message[1]
|
is_live = message[1]
|
||||||
item = message[0]
|
item = message[0]
|
||||||
log.debug(u'Startup called with message %s' % message)
|
|
||||||
hide_mode = message[2]
|
hide_mode = message[2]
|
||||||
file = item.get_frame_path()
|
file = item.get_frame_path()
|
||||||
self.handler = item.title
|
self.handler = item.processor
|
||||||
if self.handler == self.media_item.Automatic:
|
if self.handler == self.media_item.Automatic:
|
||||||
self.handler = self.media_item.findControllerByType(file)
|
self.handler = self.media_item.findControllerByType(file)
|
||||||
if not self.handler:
|
if not self.handler:
|
||||||
|
@ -331,7 +328,7 @@ class MessageListener(object):
|
||||||
|
|
||||||
def slide(self, message):
|
def slide(self, message):
|
||||||
"""
|
"""
|
||||||
React to the message to move to a specific slide
|
React to the message to move to a specific slide.
|
||||||
"""
|
"""
|
||||||
is_live = message[1]
|
is_live = message[1]
|
||||||
slide = message[2]
|
slide = message[2]
|
||||||
|
@ -342,7 +339,7 @@ class MessageListener(object):
|
||||||
|
|
||||||
def first(self, message):
|
def first(self, message):
|
||||||
"""
|
"""
|
||||||
React to the message to move to the first slide
|
React to the message to move to the first slide.
|
||||||
"""
|
"""
|
||||||
is_live = message[1]
|
is_live = message[1]
|
||||||
if is_live:
|
if is_live:
|
||||||
|
@ -352,7 +349,7 @@ class MessageListener(object):
|
||||||
|
|
||||||
def last(self, message):
|
def last(self, message):
|
||||||
"""
|
"""
|
||||||
React to the message to move to the last slide
|
React to the message to move to the last slide.
|
||||||
"""
|
"""
|
||||||
is_live = message[1]
|
is_live = message[1]
|
||||||
if is_live:
|
if is_live:
|
||||||
|
@ -362,7 +359,7 @@ class MessageListener(object):
|
||||||
|
|
||||||
def next(self, message):
|
def next(self, message):
|
||||||
"""
|
"""
|
||||||
React to the message to move to the next animation/slide
|
React to the message to move to the next animation/slide.
|
||||||
"""
|
"""
|
||||||
is_live = message[1]
|
is_live = message[1]
|
||||||
if is_live:
|
if is_live:
|
||||||
|
@ -372,7 +369,7 @@ class MessageListener(object):
|
||||||
|
|
||||||
def previous(self, message):
|
def previous(self, message):
|
||||||
"""
|
"""
|
||||||
React to the message to move to the previous animation/slide
|
React to the message to move to the previous animation/slide.
|
||||||
"""
|
"""
|
||||||
is_live = message[1]
|
is_live = message[1]
|
||||||
if is_live:
|
if is_live:
|
||||||
|
@ -382,8 +379,7 @@ class MessageListener(object):
|
||||||
|
|
||||||
def shutdown(self, message):
|
def shutdown(self, message):
|
||||||
"""
|
"""
|
||||||
React to message to shutdown the presentation. I.e. end the show
|
React to message to shutdown the presentation. I.e. end the show and close the file.
|
||||||
and close the file
|
|
||||||
"""
|
"""
|
||||||
is_live = message[1]
|
is_live = message[1]
|
||||||
if is_live:
|
if is_live:
|
||||||
|
@ -393,7 +389,7 @@ class MessageListener(object):
|
||||||
|
|
||||||
def hide(self, message):
|
def hide(self, message):
|
||||||
"""
|
"""
|
||||||
React to the message to show the desktop
|
React to the message to show the desktop.
|
||||||
"""
|
"""
|
||||||
is_live = message[1]
|
is_live = message[1]
|
||||||
if is_live:
|
if is_live:
|
||||||
|
@ -401,7 +397,7 @@ class MessageListener(object):
|
||||||
|
|
||||||
def blank(self, message):
|
def blank(self, message):
|
||||||
"""
|
"""
|
||||||
React to the message to blank the display
|
React to the message to blank the display.
|
||||||
"""
|
"""
|
||||||
is_live = message[1]
|
is_live = message[1]
|
||||||
hide_mode = message[2]
|
hide_mode = message[2]
|
||||||
|
@ -410,7 +406,7 @@ class MessageListener(object):
|
||||||
|
|
||||||
def unblank(self, message):
|
def unblank(self, message):
|
||||||
"""
|
"""
|
||||||
React to the message to unblank the display
|
React to the message to unblank the display.
|
||||||
"""
|
"""
|
||||||
is_live = message[1]
|
is_live = message[1]
|
||||||
if is_live:
|
if is_live:
|
||||||
|
@ -418,9 +414,7 @@ class MessageListener(object):
|
||||||
|
|
||||||
def timeout(self):
|
def timeout(self):
|
||||||
"""
|
"""
|
||||||
The presentation may be timed or might be controlled by the
|
The presentation may be timed or might be controlled by the application directly, rather than through OpenLP.
|
||||||
application directly, rather than through OpenLP. Poll occasionally
|
Poll occasionally to check which slide is currently displayed so the slidecontroller view can be updated.
|
||||||
to check which slide is currently displayed so the slidecontroller
|
|
||||||
view can be updated
|
|
||||||
"""
|
"""
|
||||||
self.live_handler.poll()
|
self.live_handler.poll()
|
||||||
|
|
|
@ -26,7 +26,10 @@
|
||||||
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
|
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
|
||||||
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
"""
|
||||||
|
This modul is for controlling powerpiont. PPT API documentation:
|
||||||
|
`http://msdn.microsoft.com/en-us/library/aa269321(office.10).aspx`_
|
||||||
|
"""
|
||||||
import os
|
import os
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
@ -39,16 +42,14 @@ if os.name == u'nt':
|
||||||
from openlp.core.lib import ScreenList
|
from openlp.core.lib import ScreenList
|
||||||
from presentationcontroller import PresentationController, PresentationDocument
|
from presentationcontroller import PresentationController, PresentationDocument
|
||||||
|
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
# PPT API documentation:
|
|
||||||
# http://msdn.microsoft.com/en-us/library/aa269321(office.10).aspx
|
|
||||||
|
|
||||||
class PowerpointController(PresentationController):
|
class PowerpointController(PresentationController):
|
||||||
"""
|
"""
|
||||||
Class to control interactions with PowerPoint Presentations
|
Class to control interactions with PowerPoint Presentations. It creates the runtime Environment , Loads the and
|
||||||
It creates the runtime Environment , Loads the and Closes the Presentation
|
Closes the Presentation. As well as triggering the correct activities based on the users input.
|
||||||
As well as triggering the correct activities based on the users input
|
|
||||||
"""
|
"""
|
||||||
log.info(u'PowerpointController loaded')
|
log.info(u'PowerpointController loaded')
|
||||||
|
|
||||||
|
@ -63,7 +64,7 @@ class PowerpointController(PresentationController):
|
||||||
|
|
||||||
def check_available(self):
|
def check_available(self):
|
||||||
"""
|
"""
|
||||||
PowerPoint is able to run on this machine
|
PowerPoint is able to run on this machine.
|
||||||
"""
|
"""
|
||||||
log.debug(u'check_available')
|
log.debug(u'check_available')
|
||||||
if os.name == u'nt':
|
if os.name == u'nt':
|
||||||
|
@ -77,7 +78,7 @@ class PowerpointController(PresentationController):
|
||||||
if os.name == u'nt':
|
if os.name == u'nt':
|
||||||
def start_process(self):
|
def start_process(self):
|
||||||
"""
|
"""
|
||||||
Loads PowerPoint process
|
Loads PowerPoint process.
|
||||||
"""
|
"""
|
||||||
log.debug(u'start_process')
|
log.debug(u'start_process')
|
||||||
if not self.process:
|
if not self.process:
|
||||||
|
@ -87,7 +88,7 @@ class PowerpointController(PresentationController):
|
||||||
|
|
||||||
def kill(self):
|
def kill(self):
|
||||||
"""
|
"""
|
||||||
Called at system exit to clean up any running presentations
|
Called at system exit to clean up any running presentations.
|
||||||
"""
|
"""
|
||||||
log.debug(u'Kill powerpoint')
|
log.debug(u'Kill powerpoint')
|
||||||
while self.docs:
|
while self.docs:
|
||||||
|
@ -105,12 +106,12 @@ class PowerpointController(PresentationController):
|
||||||
|
|
||||||
class PowerpointDocument(PresentationDocument):
|
class PowerpointDocument(PresentationDocument):
|
||||||
"""
|
"""
|
||||||
Class which holds information and controls a single presentation
|
Class which holds information and controls a single presentation.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, controller, presentation):
|
def __init__(self, controller, presentation):
|
||||||
"""
|
"""
|
||||||
Constructor, store information about the file and initialise
|
Constructor, store information about the file and initialise.
|
||||||
"""
|
"""
|
||||||
log.debug(u'Init Presentation Powerpoint')
|
log.debug(u'Init Presentation Powerpoint')
|
||||||
PresentationDocument.__init__(self, controller, presentation)
|
PresentationDocument.__init__(self, controller, presentation)
|
||||||
|
@ -118,8 +119,8 @@ class PowerpointDocument(PresentationDocument):
|
||||||
|
|
||||||
def load_presentation(self):
|
def load_presentation(self):
|
||||||
"""
|
"""
|
||||||
Called when a presentation is added to the SlideController.
|
Called when a presentation is added to the SlideController. Opens the PowerPoint file using the process created
|
||||||
Opens the PowerPoint file using the process created earlier.
|
earlier.
|
||||||
"""
|
"""
|
||||||
log.debug(u'load_presentation')
|
log.debug(u'load_presentation')
|
||||||
if not self.controller.process or not self.controller.process.Visible:
|
if not self.controller.process or not self.controller.process.Visible:
|
||||||
|
@ -142,20 +143,19 @@ class PowerpointDocument(PresentationDocument):
|
||||||
self.presentation.Slides[n].Copy()
|
self.presentation.Slides[n].Copy()
|
||||||
thumbnail = QApplication.clipboard.image()
|
thumbnail = QApplication.clipboard.image()
|
||||||
|
|
||||||
However, for the moment, we want a physical file since it makes life
|
However, for the moment, we want a physical file since it makes life easier elsewhere.
|
||||||
easier elsewhere.
|
|
||||||
"""
|
"""
|
||||||
log.debug(u'create_thumbnails')
|
log.debug(u'create_thumbnails')
|
||||||
if self.check_thumbnails():
|
if self.check_thumbnails():
|
||||||
return
|
return
|
||||||
for num in range(self.presentation.Slides.Count):
|
for num in range(self.presentation.Slides.Count):
|
||||||
self.presentation.Slides(num + 1).Export(os.path.join(
|
self.presentation.Slides(num + 1).Export(
|
||||||
self.get_thumbnail_folder(), 'slide%d.png' % (num + 1)), 'png', 320, 240)
|
os.path.join(self.get_thumbnail_folder(), 'slide%d.png' % (num + 1)), 'png', 320, 240)
|
||||||
|
|
||||||
def close_presentation(self):
|
def close_presentation(self):
|
||||||
"""
|
"""
|
||||||
Close presentation and clean up objects. This is triggered by a new
|
Close presentation and clean up objects. This is triggered by a new object being added to SlideController or
|
||||||
object being added to SlideController or OpenLP being shut down.
|
OpenLP being shut down.
|
||||||
"""
|
"""
|
||||||
log.debug(u'ClosePresentation')
|
log.debug(u'ClosePresentation')
|
||||||
if self.presentation:
|
if self.presentation:
|
||||||
|
@ -182,7 +182,6 @@ class PowerpointDocument(PresentationDocument):
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def is_active(self):
|
def is_active(self):
|
||||||
"""
|
"""
|
||||||
Returns ``True`` if a presentation is currently active.
|
Returns ``True`` if a presentation is currently active.
|
||||||
|
@ -253,15 +252,14 @@ class PowerpointDocument(PresentationDocument):
|
||||||
dpi = win32ui.GetForegroundWindow().GetDC().GetDeviceCaps(88)
|
dpi = win32ui.GetForegroundWindow().GetDC().GetDeviceCaps(88)
|
||||||
except win32ui.error:
|
except win32ui.error:
|
||||||
dpi = 96
|
dpi = 96
|
||||||
rect = ScreenList().current[u'size']
|
size = ScreenList().current[u'size']
|
||||||
ppt_window = self.presentation.SlideShowSettings.Run()
|
ppt_window = self.presentation.SlideShowSettings.Run()
|
||||||
if not ppt_window:
|
if not ppt_window:
|
||||||
return
|
return
|
||||||
ppt_window.Top = rect.y() * 72 / dpi
|
ppt_window.Top = size.y() * 72 / dpi
|
||||||
ppt_window.Height = rect.height() * 72 / dpi
|
ppt_window.Height = size.height() * 72 / dpi
|
||||||
ppt_window.Left = rect.x() * 72 / dpi
|
ppt_window.Left = size.x() * 72 / dpi
|
||||||
ppt_window.Width = rect.width() * 72 / dpi
|
ppt_window.Width = size.width() * 72 / dpi
|
||||||
|
|
||||||
|
|
||||||
def get_slide_number(self):
|
def get_slide_number(self):
|
||||||
"""
|
"""
|
||||||
|
@ -318,6 +316,7 @@ class PowerpointDocument(PresentationDocument):
|
||||||
"""
|
"""
|
||||||
return _get_text_from_shapes(self.presentation.Slides(slide_no).NotesPage.Shapes)
|
return _get_text_from_shapes(self.presentation.Slides(slide_no).NotesPage.Shapes)
|
||||||
|
|
||||||
|
|
||||||
def _get_text_from_shapes(shapes):
|
def _get_text_from_shapes(shapes):
|
||||||
"""
|
"""
|
||||||
Returns any text extracted from the shapes on a presentation slide.
|
Returns any text extracted from the shapes on a presentation slide.
|
||||||
|
@ -326,8 +325,8 @@ def _get_text_from_shapes(shapes):
|
||||||
A set of shapes to search for text.
|
A set of shapes to search for text.
|
||||||
"""
|
"""
|
||||||
text = ''
|
text = ''
|
||||||
for idx in range(shapes.Count):
|
for index in range(shapes.Count):
|
||||||
shape = shapes(idx + 1)
|
shape = shapes(index + 1)
|
||||||
if shape.HasTextFrame:
|
if shape.HasTextFrame:
|
||||||
text += shape.TextFrame.TextRange.Text + '\n'
|
text += shape.TextFrame.TextRange.Text + '\n'
|
||||||
return text
|
return text
|
||||||
|
|
|
@ -37,13 +37,14 @@ if os.name == u'nt':
|
||||||
from openlp.core.lib import ScreenList
|
from openlp.core.lib import ScreenList
|
||||||
from presentationcontroller import PresentationController, PresentationDocument
|
from presentationcontroller import PresentationController, PresentationDocument
|
||||||
|
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class PptviewController(PresentationController):
|
class PptviewController(PresentationController):
|
||||||
"""
|
"""
|
||||||
Class to control interactions with PowerPoint Viewer Presentations
|
Class to control interactions with PowerPoint Viewer Presentations. It creates the runtime Environment , Loads the
|
||||||
It creates the runtime Environment , Loads the and Closes the Presentation
|
and Closes the Presentation. As well as triggering the correct activities based on the users input
|
||||||
As well as triggering the correct activities based on the users input
|
|
||||||
"""
|
"""
|
||||||
log.info(u'PPTViewController loaded')
|
log.info(u'PPTViewController loaded')
|
||||||
|
|
||||||
|
@ -58,7 +59,7 @@ class PptviewController(PresentationController):
|
||||||
|
|
||||||
def check_available(self):
|
def check_available(self):
|
||||||
"""
|
"""
|
||||||
PPT Viewer is able to run on this machine
|
PPT Viewer is able to run on this machine.
|
||||||
"""
|
"""
|
||||||
log.debug(u'check_available')
|
log.debug(u'check_available')
|
||||||
if os.name != u'nt':
|
if os.name != u'nt':
|
||||||
|
@ -68,7 +69,7 @@ class PptviewController(PresentationController):
|
||||||
if os.name == u'nt':
|
if os.name == u'nt':
|
||||||
def check_installed(self):
|
def check_installed(self):
|
||||||
"""
|
"""
|
||||||
Check the viewer is installed
|
Check the viewer is installed.
|
||||||
"""
|
"""
|
||||||
log.debug(u'Check installed')
|
log.debug(u'Check installed')
|
||||||
try:
|
try:
|
||||||
|
@ -79,14 +80,14 @@ class PptviewController(PresentationController):
|
||||||
|
|
||||||
def start_process(self):
|
def start_process(self):
|
||||||
"""
|
"""
|
||||||
Loads the PPTVIEWLIB library
|
Loads the PPTVIEWLIB library.
|
||||||
"""
|
"""
|
||||||
if self.process:
|
if self.process:
|
||||||
return
|
return
|
||||||
log.debug(u'start PPTView')
|
log.debug(u'start PPTView')
|
||||||
dllpath = os.path.join(self.plugin_manager.base_path, u'presentations', u'lib', u'pptviewlib',
|
dll_path = os.path.join(
|
||||||
u'pptviewlib.dll')
|
self.plugin_manager.base_path, u'presentations', u'lib', u'pptviewlib', u'pptviewlib.dll')
|
||||||
self.process = cdll.LoadLibrary(dllpath)
|
self.process = cdll.LoadLibrary(dll_path)
|
||||||
if log.isEnabledFor(logging.DEBUG):
|
if log.isEnabledFor(logging.DEBUG):
|
||||||
self.process.SetDebug(1)
|
self.process.SetDebug(1)
|
||||||
|
|
||||||
|
@ -101,33 +102,32 @@ class PptviewController(PresentationController):
|
||||||
|
|
||||||
class PptviewDocument(PresentationDocument):
|
class PptviewDocument(PresentationDocument):
|
||||||
"""
|
"""
|
||||||
Class which holds information and controls a single presentation
|
Class which holds information and controls a single presentation.
|
||||||
"""
|
"""
|
||||||
def __init__(self, controller, presentation):
|
def __init__(self, controller, presentation):
|
||||||
"""
|
"""
|
||||||
Constructor, store information about the file and initialise
|
Constructor, store information about the file and initialise.
|
||||||
"""
|
"""
|
||||||
log.debug(u'Init Presentation PowerPoint')
|
log.debug(u'Init Presentation PowerPoint')
|
||||||
PresentationDocument.__init__(self, controller, presentation)
|
PresentationDocument.__init__(self, controller, presentation)
|
||||||
self.presentation = None
|
self.presentation = None
|
||||||
self.pptid = None
|
self.ppt_id = None
|
||||||
self.blanked = False
|
self.blanked = False
|
||||||
self.hidden = False
|
self.hidden = False
|
||||||
|
|
||||||
def load_presentation(self):
|
def load_presentation(self):
|
||||||
"""
|
"""
|
||||||
Called when a presentation is added to the SlideController.
|
Called when a presentation is added to the SlideController. It builds the environment, starts communication with
|
||||||
It builds the environment, starts communication with the background
|
the background PptView task started earlier.
|
||||||
PptView task started earlier.
|
|
||||||
"""
|
"""
|
||||||
log.debug(u'LoadPresentation')
|
log.debug(u'LoadPresentation')
|
||||||
rect = ScreenList().current[u'size']
|
size = ScreenList().current[u'size']
|
||||||
rect = RECT(rect.x(), rect.y(), rect.right(), rect.bottom())
|
rect = RECT(size.x(), size.y(), size.right(), size.bottom())
|
||||||
filepath = str(self.filepath.replace(u'/', u'\\'))
|
filepath = str(self.filepath.replace(u'/', u'\\'))
|
||||||
if not os.path.isdir(self.get_temp_folder()):
|
if not os.path.isdir(self.get_temp_folder()):
|
||||||
os.makedirs(self.get_temp_folder())
|
os.makedirs(self.get_temp_folder())
|
||||||
self.pptid = self.controller.process.OpenPPT(filepath, None, rect, str(self.get_temp_folder()) + '\\slide')
|
self.ppt_id = self.controller.process.OpenPPT(filepath, None, rect, str(self.get_temp_folder()) + '\\slide')
|
||||||
if self.pptid >= 0:
|
if self.ppt_id >= 0:
|
||||||
self.create_thumbnails()
|
self.create_thumbnails()
|
||||||
self.stop_presentation()
|
self.stop_presentation()
|
||||||
return True
|
return True
|
||||||
|
@ -136,8 +136,7 @@ class PptviewDocument(PresentationDocument):
|
||||||
|
|
||||||
def create_thumbnails(self):
|
def create_thumbnails(self):
|
||||||
"""
|
"""
|
||||||
PPTviewLib creates large BMP's, but we want small PNG's for consistency.
|
PPTviewLib creates large BMP's, but we want small PNG's for consistency. Convert them here.
|
||||||
Convert them here.
|
|
||||||
"""
|
"""
|
||||||
log.debug(u'create_thumbnails')
|
log.debug(u'create_thumbnails')
|
||||||
if self.check_thumbnails():
|
if self.check_thumbnails():
|
||||||
|
@ -149,21 +148,20 @@ class PptviewDocument(PresentationDocument):
|
||||||
|
|
||||||
def close_presentation(self):
|
def close_presentation(self):
|
||||||
"""
|
"""
|
||||||
Close presentation and clean up objects
|
Close presentation and clean up objects. Triggered by new object being added to SlideController or OpenLP being
|
||||||
Triggered by new object being added to SlideController orOpenLP
|
shut down.
|
||||||
being shut down
|
|
||||||
"""
|
"""
|
||||||
log.debug(u'ClosePresentation')
|
log.debug(u'ClosePresentation')
|
||||||
if self.controller.process:
|
if self.controller.process:
|
||||||
self.controller.process.ClosePPT(self.pptid)
|
self.controller.process.ClosePPT(self.ppt_id)
|
||||||
self.pptid = -1
|
self.ppt_id = -1
|
||||||
self.controller.remove_doc(self)
|
self.controller.remove_doc(self)
|
||||||
|
|
||||||
def is_loaded(self):
|
def is_loaded(self):
|
||||||
"""
|
"""
|
||||||
Returns true if a presentation is loaded
|
Returns true if a presentation is loaded.
|
||||||
"""
|
"""
|
||||||
if self.pptid < 0:
|
if self.ppt_id < 0:
|
||||||
return False
|
return False
|
||||||
if self.get_slide_count() < 0:
|
if self.get_slide_count() < 0:
|
||||||
return False
|
return False
|
||||||
|
@ -171,74 +169,74 @@ class PptviewDocument(PresentationDocument):
|
||||||
|
|
||||||
def is_active(self):
|
def is_active(self):
|
||||||
"""
|
"""
|
||||||
Returns true if a presentation is currently active
|
Returns true if a presentation is currently active.
|
||||||
"""
|
"""
|
||||||
return self.is_loaded() and not self.hidden
|
return self.is_loaded() and not self.hidden
|
||||||
|
|
||||||
def blank_screen(self):
|
def blank_screen(self):
|
||||||
"""
|
"""
|
||||||
Blanks the screen
|
Blanks the screen.
|
||||||
"""
|
"""
|
||||||
self.controller.process.Blank(self.pptid)
|
self.controller.process.Blank(self.ppt_id)
|
||||||
self.blanked = True
|
self.blanked = True
|
||||||
|
|
||||||
def unblank_screen(self):
|
def unblank_screen(self):
|
||||||
"""
|
"""
|
||||||
Unblanks (restores) the presentation
|
Unblanks (restores) the presentation.
|
||||||
"""
|
"""
|
||||||
self.controller.process.Unblank(self.pptid)
|
self.controller.process.Unblank(self.ppt_id)
|
||||||
self.blanked = False
|
self.blanked = False
|
||||||
|
|
||||||
def is_blank(self):
|
def is_blank(self):
|
||||||
"""
|
"""
|
||||||
Returns true if screen is blank
|
Returns true if screen is blank.
|
||||||
"""
|
"""
|
||||||
log.debug(u'is blank OpenOffice')
|
log.debug(u'is blank OpenOffice')
|
||||||
return self.blanked
|
return self.blanked
|
||||||
|
|
||||||
def stop_presentation(self):
|
def stop_presentation(self):
|
||||||
"""
|
"""
|
||||||
Stops the current presentation and hides the output
|
Stops the current presentation and hides the output.
|
||||||
"""
|
"""
|
||||||
self.hidden = True
|
self.hidden = True
|
||||||
self.controller.process.Stop(self.pptid)
|
self.controller.process.Stop(self.ppt_id)
|
||||||
|
|
||||||
def start_presentation(self):
|
def start_presentation(self):
|
||||||
"""
|
"""
|
||||||
Starts a presentation from the beginning
|
Starts a presentation from the beginning.
|
||||||
"""
|
"""
|
||||||
if self.hidden:
|
if self.hidden:
|
||||||
self.hidden = False
|
self.hidden = False
|
||||||
self.controller.process.Resume(self.pptid)
|
self.controller.process.Resume(self.ppt_id)
|
||||||
else:
|
else:
|
||||||
self.controller.process.RestartShow(self.pptid)
|
self.controller.process.RestartShow(self.ppt_id)
|
||||||
|
|
||||||
def get_slide_number(self):
|
def get_slide_number(self):
|
||||||
"""
|
"""
|
||||||
Returns the current slide number
|
Returns the current slide number.
|
||||||
"""
|
"""
|
||||||
return self.controller.process.GetCurrentSlide(self.pptid)
|
return self.controller.process.GetCurrentSlide(self.ppt_id)
|
||||||
|
|
||||||
def get_slide_count(self):
|
def get_slide_count(self):
|
||||||
"""
|
"""
|
||||||
Returns total number of slides
|
Returns total number of slides.
|
||||||
"""
|
"""
|
||||||
return self.controller.process.GetSlideCount(self.pptid)
|
return self.controller.process.GetSlideCount(self.ppt_id)
|
||||||
|
|
||||||
def goto_slide(self, slideno):
|
def goto_slide(self, slideno):
|
||||||
"""
|
"""
|
||||||
Moves to a specific slide in the presentation
|
Moves to a specific slide in the presentation.
|
||||||
"""
|
"""
|
||||||
self.controller.process.GotoSlide(self.pptid, slideno)
|
self.controller.process.GotoSlide(self.ppt_id, slideno)
|
||||||
|
|
||||||
def next_step(self):
|
def next_step(self):
|
||||||
"""
|
"""
|
||||||
Triggers the next effect of slide on the running presentation
|
Triggers the next effect of slide on the running presentation.
|
||||||
"""
|
"""
|
||||||
self.controller.process.NextStep(self.pptid)
|
self.controller.process.NextStep(self.ppt_id)
|
||||||
|
|
||||||
def previous_step(self):
|
def previous_step(self):
|
||||||
"""
|
"""
|
||||||
Triggers the previous slide on the running presentation
|
Triggers the previous slide on the running presentation.
|
||||||
"""
|
"""
|
||||||
self.controller.process.PrevStep(self.pptid)
|
self.controller.process.PrevStep(self.ppt_id)
|
||||||
|
|
|
@ -38,11 +38,11 @@ from openlp.core.utils import AppLocation
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class PresentationDocument(object):
|
class PresentationDocument(object):
|
||||||
"""
|
"""
|
||||||
Base class for presentation documents to inherit from.
|
Base class for presentation documents to inherit from. Loads and closes the presentation as well as triggering the
|
||||||
Loads and closes the presentation as well as triggering the correct
|
correct activities based on the users input
|
||||||
activities based on the users input
|
|
||||||
|
|
||||||
**Hook Functions**
|
**Hook Functions**
|
||||||
|
|
||||||
|
@ -131,20 +131,17 @@ class PresentationDocument(object):
|
||||||
"""
|
"""
|
||||||
The location where thumbnail images will be stored
|
The location where thumbnail images will be stored
|
||||||
"""
|
"""
|
||||||
return os.path.join(
|
return os.path.join(self.controller.thumbnail_folder, self.get_file_name())
|
||||||
self.controller.thumbnail_folder, self.get_file_name())
|
|
||||||
|
|
||||||
def get_temp_folder(self):
|
def get_temp_folder(self):
|
||||||
"""
|
"""
|
||||||
The location where thumbnail images will be stored
|
The location where thumbnail images will be stored
|
||||||
"""
|
"""
|
||||||
return os.path.join(
|
return os.path.join(self.controller.temp_folder, self.get_file_name())
|
||||||
self.controller.temp_folder, self.get_file_name())
|
|
||||||
|
|
||||||
def check_thumbnails(self):
|
def check_thumbnails(self):
|
||||||
"""
|
"""
|
||||||
Returns ``True`` if the thumbnail images exist and are more recent than
|
Returns ``True`` if the thumbnail images exist and are more recent than the powerpoint file.
|
||||||
the powerpoint file.
|
|
||||||
"""
|
"""
|
||||||
lastimage = self.get_thumbnail_path(self.get_slide_count(), True)
|
lastimage = self.get_thumbnail_path(self.get_slide_count(), True)
|
||||||
if not (lastimage and os.path.isfile(lastimage)):
|
if not (lastimage and os.path.isfile(lastimage)):
|
||||||
|
@ -153,8 +150,7 @@ class PresentationDocument(object):
|
||||||
|
|
||||||
def close_presentation(self):
|
def close_presentation(self):
|
||||||
"""
|
"""
|
||||||
Close presentation and clean up objects
|
Close presentation and clean up objects. Triggered by new object being added to SlideController
|
||||||
Triggered by new object being added to SlideController
|
|
||||||
"""
|
"""
|
||||||
self.controller.close_presentation()
|
self.controller.close_presentation()
|
||||||
|
|
||||||
|
@ -223,8 +219,8 @@ class PresentationDocument(object):
|
||||||
|
|
||||||
def next_step(self):
|
def next_step(self):
|
||||||
"""
|
"""
|
||||||
Triggers the next effect of slide on the running presentation
|
Triggers the next effect of slide on the running presentation. This might be the next animation on the current
|
||||||
This might be the next animation on the current slide, or the next slide
|
slide, or the next slide
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -236,8 +232,7 @@ class PresentationDocument(object):
|
||||||
|
|
||||||
def convert_thumbnail(self, file, idx):
|
def convert_thumbnail(self, file, idx):
|
||||||
"""
|
"""
|
||||||
Convert the slide image the application made to a standard 320x240
|
Convert the slide image the application made to a standard 320x240 .png image.
|
||||||
.png image.
|
|
||||||
"""
|
"""
|
||||||
if self.check_thumbnails():
|
if self.check_thumbnails():
|
||||||
return
|
return
|
||||||
|
@ -281,7 +276,7 @@ class PresentationDocument(object):
|
||||||
Returns the text on the slide
|
Returns the text on the slide
|
||||||
|
|
||||||
``slide_no``
|
``slide_no``
|
||||||
The slide the text is required for, starting at 1
|
The slide the text is required for, starting at 1
|
||||||
"""
|
"""
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
|
@ -290,24 +285,21 @@ class PresentationDocument(object):
|
||||||
Returns the text on the slide
|
Returns the text on the slide
|
||||||
|
|
||||||
``slide_no``
|
``slide_no``
|
||||||
The slide the notes are required for, starting at 1
|
The slide the notes are required for, starting at 1
|
||||||
"""
|
"""
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
|
|
||||||
class PresentationController(object):
|
class PresentationController(object):
|
||||||
"""
|
"""
|
||||||
This class is used to control interactions with presentation applications
|
This class is used to control interactions with presentation applications by creating a runtime environment. This is
|
||||||
by creating a runtime environment. This is a base class for presentation
|
a base class for presentation controllers to inherit from.
|
||||||
controllers to inherit from.
|
|
||||||
|
|
||||||
To create a new controller, take a copy of this file and name it so it ends
|
To create a new controller, take a copy of this file and name it so it ends with ``controller.py``, i.e.
|
||||||
with ``controller.py``, i.e. ``foobarcontroller.py``. Make sure it inherits
|
``foobarcontroller.py``. Make sure it inherits
|
||||||
:class:`~openlp.plugins.presentations.lib.presentationcontroller.PresentationController`,
|
:class:`~openlp.plugins.presentations.lib.presentationcontroller.PresentationController`, and then fill in the
|
||||||
and then fill in the blanks. If possible try to make sure it loads on all
|
blanks. If possible try to make sure it loads on all platforms, usually by using :mod:``os.name`` checks, although
|
||||||
platforms, usually by using :mod:``os.name`` checks, although
|
``__init__``, ``check_available`` and ``presentation_deleted`` should always be implemented.
|
||||||
``__init__``, ``check_available`` and ``presentation_deleted`` should
|
|
||||||
always be implemented.
|
|
||||||
|
|
||||||
See :class:`~openlp.plugins.presentations.lib.impresscontroller.ImpressController`,
|
See :class:`~openlp.plugins.presentations.lib.impresscontroller.ImpressController`,
|
||||||
:class:`~openlp.plugins.presentations.lib.powerpointcontroller.PowerpointController` or
|
:class:`~openlp.plugins.presentations.lib.powerpointcontroller.PowerpointController` or
|
||||||
|
@ -317,36 +309,34 @@ class PresentationController(object):
|
||||||
**Basic Attributes**
|
**Basic Attributes**
|
||||||
|
|
||||||
``name``
|
``name``
|
||||||
The name that appears in the options and the media manager
|
The name that appears in the options and the media manager.
|
||||||
|
|
||||||
``enabled``
|
``enabled``
|
||||||
The controller is enabled
|
The controller is enabled.
|
||||||
|
|
||||||
``available``
|
``available``
|
||||||
The controller is available on this machine. Set by init via
|
The controller is available on this machine. Set by init via call to check_available.
|
||||||
call to check_available
|
|
||||||
|
|
||||||
``plugin``
|
``plugin``
|
||||||
The presentationplugin object
|
The presentationplugin object.
|
||||||
|
|
||||||
``supports``
|
``supports``
|
||||||
The primary native file types this application supports
|
The primary native file types this application supports.
|
||||||
|
|
||||||
``alsosupports``
|
``also_supports``
|
||||||
Other file types the application can import, although not necessarily
|
Other file types the application can import, although not necessarily the first choice due to potential
|
||||||
the first choice due to potential incompatibilities
|
incompatibilities.
|
||||||
|
|
||||||
**Hook Functions**
|
**Hook Functions**
|
||||||
|
|
||||||
``kill()``
|
``kill()``
|
||||||
Called at system exit to clean up any running presentations
|
Called at system exit to clean up any running presentations.
|
||||||
|
|
||||||
``check_available()``
|
``check_available()``
|
||||||
Returns True if presentation application is installed/can run on this
|
Returns True if presentation application is installed/can run on this machine.
|
||||||
machine
|
|
||||||
|
|
||||||
``presentation_deleted()``
|
``presentation_deleted()``
|
||||||
Deletes presentation specific files, e.g. thumbnails
|
Deletes presentation specific files, e.g. thumbnails.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
log.info(u'PresentationController loaded')
|
log.info(u'PresentationController loaded')
|
||||||
|
@ -354,9 +344,8 @@ class PresentationController(object):
|
||||||
def __init__(self, plugin=None, name=u'PresentationController',
|
def __init__(self, plugin=None, name=u'PresentationController',
|
||||||
document_class=PresentationDocument):
|
document_class=PresentationDocument):
|
||||||
"""
|
"""
|
||||||
This is the constructor for the presentationcontroller object. This
|
This is the constructor for the presentationcontroller object. This provides an easy way for descendent plugins
|
||||||
provides an easy way for descendent plugins to populate common data.
|
to populate common data. This method *must* be overridden, like so::
|
||||||
This method *must* be overridden, like so::
|
|
||||||
|
|
||||||
class MyPresentationController(PresentationController):
|
class MyPresentationController(PresentationController):
|
||||||
def __init__(self, plugin):
|
def __init__(self, plugin):
|
||||||
|
@ -370,7 +359,7 @@ class PresentationController(object):
|
||||||
Name of the application, to appear in the application
|
Name of the application, to appear in the application
|
||||||
"""
|
"""
|
||||||
self.supports = []
|
self.supports = []
|
||||||
self.alsosupports = []
|
self.also_supports = []
|
||||||
self.docs = []
|
self.docs = []
|
||||||
self.plugin = plugin
|
self.plugin = plugin
|
||||||
self.name = name
|
self.name = name
|
||||||
|
@ -399,28 +388,26 @@ class PresentationController(object):
|
||||||
|
|
||||||
def check_available(self):
|
def check_available(self):
|
||||||
"""
|
"""
|
||||||
Presentation app is able to run on this machine
|
Presentation app is able to run on this machine.
|
||||||
"""
|
"""
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def start_process(self):
|
def start_process(self):
|
||||||
"""
|
"""
|
||||||
Loads a running version of the presentation application in the
|
Loads a running version of the presentation application in the background.
|
||||||
background.
|
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def kill(self):
|
def kill(self):
|
||||||
"""
|
"""
|
||||||
Called at system exit to clean up any running presentations and
|
Called at system exit to clean up any running presentations and close the application.
|
||||||
close the application
|
|
||||||
"""
|
"""
|
||||||
log.debug(u'Kill')
|
log.debug(u'Kill')
|
||||||
self.close_presentation()
|
self.close_presentation()
|
||||||
|
|
||||||
def add_document(self, name):
|
def add_document(self, name):
|
||||||
"""
|
"""
|
||||||
Called when a new presentation document is opened
|
Called when a new presentation document is opened.
|
||||||
"""
|
"""
|
||||||
document = self.document_class(self, name)
|
document = self.document_class(self, name)
|
||||||
self.docs.append(document)
|
self.docs.append(document)
|
||||||
|
@ -428,7 +415,7 @@ class PresentationController(object):
|
||||||
|
|
||||||
def remove_doc(self, doc=None):
|
def remove_doc(self, doc=None):
|
||||||
"""
|
"""
|
||||||
Called to remove an open document from the collection
|
Called to remove an open document from the collection.
|
||||||
"""
|
"""
|
||||||
log.debug(u'remove_doc Presentation')
|
log.debug(u'remove_doc Presentation')
|
||||||
if doc is None:
|
if doc is None:
|
||||||
|
|
|
@ -91,8 +91,7 @@ class PresentationTab(SettingsTab):
|
||||||
if checkbox.isEnabled():
|
if checkbox.isEnabled():
|
||||||
checkbox.setText(controller.name)
|
checkbox.setText(controller.name)
|
||||||
else:
|
else:
|
||||||
checkbox.setText(
|
checkbox.setText(translate('PresentationPlugin.PresentationTab', '%s (unavailable)') % controller.name)
|
||||||
translate('PresentationPlugin.PresentationTab', '%s (unavailable)') % controller.name)
|
|
||||||
|
|
||||||
def load(self):
|
def load(self):
|
||||||
"""
|
"""
|
||||||
|
@ -106,8 +105,8 @@ class PresentationTab(SettingsTab):
|
||||||
|
|
||||||
def save(self):
|
def save(self):
|
||||||
"""
|
"""
|
||||||
Save the settings. If the tab hasn't been made visible to the user then there is nothing to do,
|
Save the settings. If the tab hasn't been made visible to the user then there is nothing to do, so exit. This
|
||||||
so exit. This removes the need to start presentation applications unnecessarily.
|
removes the need to start presentation applications unnecessarily.
|
||||||
"""
|
"""
|
||||||
if not self.activated:
|
if not self.activated:
|
||||||
return
|
return
|
||||||
|
|
|
@ -27,8 +27,8 @@
|
||||||
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
||||||
###############################################################################
|
###############################################################################
|
||||||
"""
|
"""
|
||||||
The :mod:`presentationplugin` module provides the ability for OpenLP to display
|
The :mod:`presentationplugin` module provides the ability for OpenLP to display presentations from a variety of document
|
||||||
presentations from a variety of document formats.
|
formats.
|
||||||
"""
|
"""
|
||||||
import os
|
import os
|
||||||
import logging
|
import logging
|
||||||
|
@ -39,22 +39,23 @@ from openlp.core.lib import Plugin, StringContent, build_icon, translate
|
||||||
from openlp.core.utils import AppLocation
|
from openlp.core.utils import AppLocation
|
||||||
from openlp.plugins.presentations.lib import PresentationController, PresentationMediaItem, PresentationTab
|
from openlp.plugins.presentations.lib import PresentationController, PresentationMediaItem, PresentationTab
|
||||||
|
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
__default_settings__ = {
|
__default_settings__ = {
|
||||||
u'presentations/override app': QtCore.Qt.Unchecked,
|
u'presentations/override app': QtCore.Qt.Unchecked,
|
||||||
u'presentations/Impress': QtCore.Qt.Checked,
|
u'presentations/Impress': QtCore.Qt.Checked,
|
||||||
u'presentations/Powerpoint': QtCore.Qt.Checked,
|
u'presentations/Powerpoint': QtCore.Qt.Checked,
|
||||||
u'presentations/Powerpoint Viewer': QtCore.Qt.Checked,
|
u'presentations/Powerpoint Viewer': QtCore.Qt.Checked,
|
||||||
u'presentations/presentations files': []
|
u'presentations/presentations files': []
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class PresentationPlugin(Plugin):
|
class PresentationPlugin(Plugin):
|
||||||
"""
|
"""
|
||||||
This plugin allowed a Presentation to be opened, controlled and displayed
|
This plugin allowed a Presentation to be opened, controlled and displayed on the output display. The plugin controls
|
||||||
on the output display. The plugin controls third party applications such
|
third party applications such as OpenOffice.org Impress, Microsoft PowerPoint and the PowerPoint viewer.
|
||||||
as OpenOffice.org Impress, Microsoft PowerPoint and the PowerPoint viewer
|
|
||||||
"""
|
"""
|
||||||
log = logging.getLogger(u'PresentationPlugin')
|
log = logging.getLogger(u'PresentationPlugin')
|
||||||
|
|
||||||
|
@ -69,18 +70,16 @@ class PresentationPlugin(Plugin):
|
||||||
self.icon_path = u':/plugins/plugin_presentations.png'
|
self.icon_path = u':/plugins/plugin_presentations.png'
|
||||||
self.icon = build_icon(self.icon_path)
|
self.icon = build_icon(self.icon_path)
|
||||||
|
|
||||||
def create_settings_Tab(self, parent):
|
def create_settings_tab(self, parent):
|
||||||
"""
|
"""
|
||||||
Create the settings Tab
|
Create the settings Tab.
|
||||||
"""
|
"""
|
||||||
visible_name = self.get_string(StringContent.VisibleName)
|
visible_name = self.get_string(StringContent.VisibleName)
|
||||||
self.settings_tab = PresentationTab(parent, self.name, visible_name[u'title'], self.controllers,
|
self.settings_tab = PresentationTab(parent, self.name, visible_name[u'title'], self.controllers, self.icon_path)
|
||||||
self.icon_path)
|
|
||||||
|
|
||||||
def initialise(self):
|
def initialise(self):
|
||||||
"""
|
"""
|
||||||
Initialise the plugin. Determine which controllers are enabled
|
Initialise the plugin. Determine which controllers are enabled are start their processes.
|
||||||
are start their processes.
|
|
||||||
"""
|
"""
|
||||||
log.info(u'Presentations Initialising')
|
log.info(u'Presentations Initialising')
|
||||||
Plugin.initialise(self)
|
Plugin.initialise(self)
|
||||||
|
@ -95,8 +94,8 @@ class PresentationPlugin(Plugin):
|
||||||
|
|
||||||
def finalise(self):
|
def finalise(self):
|
||||||
"""
|
"""
|
||||||
Finalise the plugin. Ask all the enabled presentation applications
|
Finalise the plugin. Ask all the enabled presentation applications to close down their applications and release
|
||||||
to close down their applications and release resources.
|
resources.
|
||||||
"""
|
"""
|
||||||
log.info(u'Plugin Finalise')
|
log.info(u'Plugin Finalise')
|
||||||
# Ask each controller to tidy up.
|
# Ask each controller to tidy up.
|
||||||
|
@ -108,26 +107,23 @@ class PresentationPlugin(Plugin):
|
||||||
|
|
||||||
def create_media_manager_item(self):
|
def create_media_manager_item(self):
|
||||||
"""
|
"""
|
||||||
Create the Media Manager List
|
Create the Media Manager List.
|
||||||
"""
|
"""
|
||||||
self.media_item = PresentationMediaItem(
|
self.media_item = PresentationMediaItem(
|
||||||
self.main_window.media_dock_manager.media_dock, self, self.icon, self.controllers)
|
self.main_window.media_dock_manager.media_dock, self, self.icon, self.controllers)
|
||||||
|
|
||||||
def register_controllers(self, controller):
|
def register_controllers(self, controller):
|
||||||
"""
|
"""
|
||||||
Register each presentation controller (Impress, PPT etc) and store for later use
|
Register each presentation controller (Impress, PPT etc) and store for later use.
|
||||||
"""
|
"""
|
||||||
self.controllers[controller.name] = controller
|
self.controllers[controller.name] = controller
|
||||||
|
|
||||||
def check_pre_conditions(self):
|
def check_pre_conditions(self):
|
||||||
"""
|
"""
|
||||||
Check to see if we have any presentation software available
|
Check to see if we have any presentation software available. If not do not install the plugin.
|
||||||
If Not do not install the plugin.
|
|
||||||
"""
|
"""
|
||||||
log.debug(u'check_pre_conditions')
|
log.debug(u'check_pre_conditions')
|
||||||
controller_dir = os.path.join(
|
controller_dir = os.path.join(AppLocation.get_directory(AppLocation.PluginsDir), u'presentations', u'lib')
|
||||||
AppLocation.get_directory(AppLocation.PluginsDir),
|
|
||||||
u'presentations', u'lib')
|
|
||||||
for filename in os.listdir(controller_dir):
|
for filename in os.listdir(controller_dir):
|
||||||
if filename.endswith(u'controller.py') and not filename == 'presentationcontroller.py':
|
if filename.endswith(u'controller.py') and not filename == 'presentationcontroller.py':
|
||||||
path = os.path.join(controller_dir, filename)
|
path = os.path.join(controller_dir, filename)
|
||||||
|
@ -146,7 +142,7 @@ class PresentationPlugin(Plugin):
|
||||||
|
|
||||||
def about(self):
|
def about(self):
|
||||||
"""
|
"""
|
||||||
Return information about this plugin
|
Return information about this plugin.
|
||||||
"""
|
"""
|
||||||
about_text = translate('PresentationPlugin', '<strong>Presentation '
|
about_text = translate('PresentationPlugin', '<strong>Presentation '
|
||||||
'Plugin</strong><br />The presentation plugin provides the '
|
'Plugin</strong><br />The presentation plugin provides the '
|
||||||
|
@ -157,7 +153,7 @@ class PresentationPlugin(Plugin):
|
||||||
|
|
||||||
def set_plugin_text_strings(self):
|
def set_plugin_text_strings(self):
|
||||||
"""
|
"""
|
||||||
Called to define all translatable texts of the plugin
|
Called to define all translatable texts of the plugin.
|
||||||
"""
|
"""
|
||||||
## Name PluginList ##
|
## Name PluginList ##
|
||||||
self.text_strings[StringContent.Name] = {
|
self.text_strings[StringContent.Name] = {
|
||||||
|
|
|
@ -147,7 +147,7 @@ window.OpenLP = {
|
||||||
},
|
},
|
||||||
pollServer: function () {
|
pollServer: function () {
|
||||||
$.getJSON(
|
$.getJSON(
|
||||||
"/api/poll",
|
"/stage/poll",
|
||||||
function (data, status) {
|
function (data, status) {
|
||||||
var prevItem = OpenLP.currentItem;
|
var prevItem = OpenLP.currentItem;
|
||||||
OpenLP.currentSlide = data.results.slide;
|
OpenLP.currentSlide = data.results.slide;
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
window.OpenLP = {
|
window.OpenLP = {
|
||||||
loadService: function (event) {
|
loadService: function (event) {
|
||||||
$.getJSON(
|
$.getJSON(
|
||||||
"/api/service/list",
|
"/stage/service/list",
|
||||||
function (data, status) {
|
function (data, status) {
|
||||||
OpenLP.nextSong = "";
|
OpenLP.nextSong = "";
|
||||||
$("#notes").html("");
|
$("#notes").html("");
|
||||||
|
@ -46,7 +46,7 @@ window.OpenLP = {
|
||||||
},
|
},
|
||||||
loadSlides: function (event) {
|
loadSlides: function (event) {
|
||||||
$.getJSON(
|
$.getJSON(
|
||||||
"/api/controller/live/text",
|
"/stage/controller/live/text",
|
||||||
function (data, status) {
|
function (data, status) {
|
||||||
OpenLP.currentSlides = data.results.slides;
|
OpenLP.currentSlides = data.results.slides;
|
||||||
OpenLP.currentSlide = 0;
|
OpenLP.currentSlide = 0;
|
||||||
|
@ -137,7 +137,7 @@ window.OpenLP = {
|
||||||
},
|
},
|
||||||
pollServer: function () {
|
pollServer: function () {
|
||||||
$.getJSON(
|
$.getJSON(
|
||||||
"/api/poll",
|
"/stage/poll",
|
||||||
function (data, status) {
|
function (data, status) {
|
||||||
OpenLP.updateClock(data);
|
OpenLP.updateClock(data);
|
||||||
if (OpenLP.currentItem != data.results.item ||
|
if (OpenLP.currentItem != data.results.item ||
|
||||||
|
|
|
@ -43,7 +43,7 @@ the remotes.
|
||||||
``/files/{filename}``
|
``/files/{filename}``
|
||||||
Serve a static file.
|
Serve a static file.
|
||||||
|
|
||||||
``/api/poll``
|
``/stage/api/poll``
|
||||||
Poll to see if there are any changes. Returns a JSON-encoded dict of
|
Poll to see if there are any changes. Returns a JSON-encoded dict of
|
||||||
any changes that occurred::
|
any changes that occurred::
|
||||||
|
|
||||||
|
@ -119,122 +119,198 @@ import os
|
||||||
import re
|
import re
|
||||||
import urllib
|
import urllib
|
||||||
import urlparse
|
import urlparse
|
||||||
|
import cherrypy
|
||||||
|
|
||||||
from PyQt4 import QtCore, QtNetwork
|
|
||||||
from mako.template import Template
|
from mako.template import Template
|
||||||
|
from PyQt4 import QtCore
|
||||||
|
|
||||||
from openlp.core.lib import Registry, Settings, PluginStatus, StringContent
|
from openlp.core.lib import Registry, Settings, PluginStatus, StringContent
|
||||||
|
|
||||||
from openlp.core.utils import AppLocation, translate
|
from openlp.core.utils import AppLocation, translate
|
||||||
|
|
||||||
|
from cherrypy._cpcompat import sha, ntob
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class HttpResponse(object):
|
def make_sha_hash(password):
|
||||||
"""
|
"""
|
||||||
A simple object to encapsulate a pseudo-http response.
|
Create an encrypted password for the given password.
|
||||||
"""
|
"""
|
||||||
code = '200 OK'
|
return sha(ntob(password)).hexdigest()
|
||||||
content = ''
|
|
||||||
headers = {
|
|
||||||
'Content-Type': 'text/html; charset="utf-8"\r\n'
|
|
||||||
}
|
|
||||||
|
|
||||||
def __init__(self, content='', headers=None, code=None):
|
|
||||||
if headers is None:
|
def fetch_password(username):
|
||||||
headers = {}
|
"""
|
||||||
self.content = content
|
Fetch the password for a provided user.
|
||||||
for key, value in headers.iteritems():
|
"""
|
||||||
self.headers[key] = value
|
if username != Settings().value(u'remotes/user id'):
|
||||||
if code:
|
return None
|
||||||
self.code = code
|
return make_sha_hash(Settings().value(u'remotes/password'))
|
||||||
|
|
||||||
|
|
||||||
class HttpServer(object):
|
class HttpServer(object):
|
||||||
"""
|
"""
|
||||||
Ability to control OpenLP via a web browser.
|
Ability to control OpenLP via a web browser.
|
||||||
|
This class controls the Cherrypy server and configuration.
|
||||||
"""
|
"""
|
||||||
def __init__(self, plugin):
|
_cp_config = {
|
||||||
|
'tools.sessions.on': True,
|
||||||
|
'tools.auth.on': True
|
||||||
|
}
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
"""
|
"""
|
||||||
Initialise the httpserver, and start the server.
|
Initialise the http server, and start the server.
|
||||||
"""
|
"""
|
||||||
log.debug(u'Initialise httpserver')
|
log.debug(u'Initialise httpserver')
|
||||||
self.plugin = plugin
|
self.settings_section = u'remotes'
|
||||||
self.html_dir = os.path.join(AppLocation.get_directory(AppLocation.PluginsDir), u'remotes', u'html')
|
self.router = HttpRouter()
|
||||||
self.connections = []
|
|
||||||
self.start_tcp()
|
|
||||||
|
|
||||||
def start_tcp(self):
|
def start_server(self):
|
||||||
"""
|
"""
|
||||||
Start the http server, use the port in the settings default to 4316.
|
Start the http server based on configuration.
|
||||||
Listen out for slide and song changes so they can be broadcast to
|
|
||||||
clients. Listen out for socket connections.
|
|
||||||
"""
|
"""
|
||||||
log.debug(u'Start TCP server')
|
log.debug(u'Start CherryPy server')
|
||||||
port = Settings().value(self.plugin.settings_section + u'/port')
|
# Define to security levels and inject the router code
|
||||||
address = Settings().value(self.plugin.settings_section + u'/ip address')
|
self.root = self.Public()
|
||||||
self.server = QtNetwork.QTcpServer()
|
self.root.files = self.Files()
|
||||||
self.server.listen(QtNetwork.QHostAddress(address), port)
|
self.root.stage = self.Stage()
|
||||||
self.server.newConnection.connect(self.new_connection)
|
self.root.router = self.router
|
||||||
log.debug(u'TCP listening on port %d' % port)
|
self.root.files.router = self.router
|
||||||
|
self.root.stage.router = self.router
|
||||||
|
cherrypy.tree.mount(self.root, '/', config=self.define_config())
|
||||||
|
# Turn off the flood of access messages cause by poll
|
||||||
|
cherrypy.log.access_log.propagate = False
|
||||||
|
cherrypy.engine.start()
|
||||||
|
|
||||||
def new_connection(self):
|
def define_config(self):
|
||||||
"""
|
"""
|
||||||
A new http connection has been made. Create a client object to handle
|
Define the configuration of the server.
|
||||||
communication.
|
|
||||||
"""
|
"""
|
||||||
log.debug(u'new http connection')
|
if Settings().value(self.settings_section + u'/https enabled'):
|
||||||
socket = self.server.nextPendingConnection()
|
port = Settings().value(self.settings_section + u'/https port')
|
||||||
if socket:
|
address = Settings().value(self.settings_section + u'/ip address')
|
||||||
self.connections.append(HttpConnection(self, socket))
|
local_data = AppLocation.get_directory(AppLocation.DataDir)
|
||||||
|
cherrypy.config.update({u'server.socket_host': str(address),
|
||||||
|
u'server.socket_port': port,
|
||||||
|
u'server.ssl_certificate': os.path.join(local_data, u'remotes', u'openlp.crt'),
|
||||||
|
u'server.ssl_private_key': os.path.join(local_data, u'remotes', u'openlp.key')})
|
||||||
|
else:
|
||||||
|
port = Settings().value(self.settings_section + u'/port')
|
||||||
|
address = Settings().value(self.settings_section + u'/ip address')
|
||||||
|
cherrypy.config.update({u'server.socket_host': str(address)})
|
||||||
|
cherrypy.config.update({u'server.socket_port': port})
|
||||||
|
cherrypy.config.update({u'environment': u'embedded'})
|
||||||
|
cherrypy.config.update({u'engine.autoreload_on': False})
|
||||||
|
directory_config = {u'/': {u'tools.staticdir.on': True,
|
||||||
|
u'tools.staticdir.dir': self.router.html_dir,
|
||||||
|
u'tools.basic_auth.on': Settings().value(u'remotes/authentication enabled'),
|
||||||
|
u'tools.basic_auth.realm': u'OpenLP Remote Login',
|
||||||
|
u'tools.basic_auth.users': fetch_password,
|
||||||
|
u'tools.basic_auth.encrypt': make_sha_hash},
|
||||||
|
u'/files': {u'tools.staticdir.on': True,
|
||||||
|
u'tools.staticdir.dir': self.router.html_dir,
|
||||||
|
u'tools.basic_auth.on': False},
|
||||||
|
u'/stage': {u'tools.staticdir.on': True,
|
||||||
|
u'tools.staticdir.dir': self.router.html_dir,
|
||||||
|
u'tools.basic_auth.on': False}}
|
||||||
|
return directory_config
|
||||||
|
|
||||||
def close_connection(self, connection):
|
class Public(object):
|
||||||
"""
|
"""
|
||||||
The connection has been closed. Clean up
|
Main access class with may have security enabled on it.
|
||||||
"""
|
"""
|
||||||
log.debug(u'close http connection')
|
@cherrypy.expose
|
||||||
if connection in self.connections:
|
def default(self, *args, **kwargs):
|
||||||
self.connections.remove(connection)
|
self.router.request_data = None
|
||||||
|
if isinstance(kwargs, dict):
|
||||||
|
self.router.request_data = kwargs.get(u'data', None)
|
||||||
|
url = urlparse.urlparse(cherrypy.url())
|
||||||
|
return self.router.process_http_request(url.path, *args)
|
||||||
|
|
||||||
|
class Files(object):
|
||||||
|
"""
|
||||||
|
Provides access to files and has no security available. These are read only accesses
|
||||||
|
"""
|
||||||
|
@cherrypy.expose
|
||||||
|
def default(self, *args, **kwargs):
|
||||||
|
url = urlparse.urlparse(cherrypy.url())
|
||||||
|
return self.router.process_http_request(url.path, *args)
|
||||||
|
|
||||||
|
class Stage(object):
|
||||||
|
"""
|
||||||
|
Stageview is read only so security is not relevant and would reduce it's usability
|
||||||
|
"""
|
||||||
|
@cherrypy.expose
|
||||||
|
def default(self, *args, **kwargs):
|
||||||
|
url = urlparse.urlparse(cherrypy.url())
|
||||||
|
return self.router.process_http_request(url.path, *args)
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
"""
|
"""
|
||||||
Close down the http server.
|
Close down the http server.
|
||||||
"""
|
"""
|
||||||
log.debug(u'close http server')
|
log.debug(u'close http server')
|
||||||
self.server.close()
|
cherrypy.engine.exit()
|
||||||
|
|
||||||
|
|
||||||
class HttpConnection(object):
|
class HttpRouter(object):
|
||||||
"""
|
"""
|
||||||
A single connection, this handles communication between the server
|
This code is called by the HttpServer upon a request and it processes it based on the routing table.
|
||||||
and the client.
|
|
||||||
"""
|
"""
|
||||||
def __init__(self, parent, socket):
|
def __init__(self):
|
||||||
"""
|
"""
|
||||||
Initialise the http connection. Listen out for socket signals.
|
Initialise the router
|
||||||
"""
|
"""
|
||||||
log.debug(u'Initialise HttpConnection: %s' % socket.peerAddress())
|
|
||||||
self.socket = socket
|
|
||||||
self.parent = parent
|
|
||||||
self.routes = [
|
self.routes = [
|
||||||
(u'^/$', self.serve_file),
|
(u'^/$', self.serve_file),
|
||||||
(u'^/(stage)$', self.serve_file),
|
(u'^/(stage)$', self.serve_file),
|
||||||
(r'^/files/(.*)$', self.serve_file),
|
(r'^/files/(.*)$', self.serve_file),
|
||||||
(r'^/api/poll$', self.poll),
|
(r'^/api/poll$', self.poll),
|
||||||
|
(r'^/stage/poll$', self.poll),
|
||||||
(r'^/api/controller/(live|preview)/(.*)$', self.controller),
|
(r'^/api/controller/(live|preview)/(.*)$', self.controller),
|
||||||
|
(r'^/stage/controller/(live|preview)/(.*)$', self.controller),
|
||||||
(r'^/api/service/(.*)$', self.service),
|
(r'^/api/service/(.*)$', self.service),
|
||||||
|
(r'^/stage/service/(.*)$', self.service),
|
||||||
(r'^/api/display/(hide|show|blank|theme|desktop)$', self.display),
|
(r'^/api/display/(hide|show|blank|theme|desktop)$', self.display),
|
||||||
(r'^/api/alert$', self.alert),
|
(r'^/api/alert$', self.alert),
|
||||||
(r'^/api/plugin/(search)$', self.pluginInfo),
|
(r'^/api/plugin/(search)$', self.plugin_info),
|
||||||
(r'^/api/(.*)/search$', self.search),
|
(r'^/api/(.*)/search$', self.search),
|
||||||
(r'^/api/(.*)/live$', self.go_live),
|
(r'^/api/(.*)/live$', self.go_live),
|
||||||
(r'^/api/(.*)/add$', self.add_to_service)
|
(r'^/api/(.*)/add$', self.add_to_service)
|
||||||
]
|
]
|
||||||
self.socket.readyRead.connect(self.ready_read)
|
|
||||||
self.socket.disconnected.connect(self.disconnected)
|
|
||||||
self.translate()
|
self.translate()
|
||||||
|
self.html_dir = os.path.join(AppLocation.get_directory(AppLocation.PluginsDir), u'remotes', u'html')
|
||||||
|
|
||||||
|
def process_http_request(self, url_path, *args):
|
||||||
|
"""
|
||||||
|
Common function to process HTTP requests
|
||||||
|
|
||||||
|
``url_path``
|
||||||
|
The requested URL.
|
||||||
|
|
||||||
|
``*args``
|
||||||
|
Any passed data.
|
||||||
|
"""
|
||||||
|
response = None
|
||||||
|
for route, func in self.routes:
|
||||||
|
match = re.match(route, url_path)
|
||||||
|
if match:
|
||||||
|
log.debug('Route "%s" matched "%s"', route, url_path)
|
||||||
|
args = []
|
||||||
|
for param in match.groups():
|
||||||
|
args.append(param)
|
||||||
|
response = func(*args)
|
||||||
|
break
|
||||||
|
if response:
|
||||||
|
return response
|
||||||
|
else:
|
||||||
|
return self._http_not_found()
|
||||||
|
|
||||||
def _get_service_items(self):
|
def _get_service_items(self):
|
||||||
|
"""
|
||||||
|
Read the service item in use and return the data as a json object
|
||||||
|
"""
|
||||||
service_items = []
|
service_items = []
|
||||||
if self.live_controller.service_item:
|
if self.live_controller.service_item:
|
||||||
current_unique_identifier = self.live_controller.service_item.unique_identifier
|
current_unique_identifier = self.live_controller.service_item.unique_identifier
|
||||||
|
@ -281,40 +357,6 @@ class HttpConnection(object):
|
||||||
'slides': translate('RemotePlugin.Mobile', 'Slides')
|
'slides': translate('RemotePlugin.Mobile', 'Slides')
|
||||||
}
|
}
|
||||||
|
|
||||||
def ready_read(self):
|
|
||||||
"""
|
|
||||||
Data has been sent from the client. Respond to it
|
|
||||||
"""
|
|
||||||
log.debug(u'ready to read socket')
|
|
||||||
if self.socket.canReadLine():
|
|
||||||
data = str(self.socket.readLine())
|
|
||||||
try:
|
|
||||||
log.debug(u'received: ' + data)
|
|
||||||
except UnicodeDecodeError:
|
|
||||||
# Malicious request containing non-ASCII characters.
|
|
||||||
self.close()
|
|
||||||
return
|
|
||||||
words = data.split(' ')
|
|
||||||
response = None
|
|
||||||
if words[0] == u'GET':
|
|
||||||
url = urlparse.urlparse(words[1])
|
|
||||||
self.url_params = urlparse.parse_qs(url.query)
|
|
||||||
# Loop through the routes we set up earlier and execute them
|
|
||||||
for route, func in self.routes:
|
|
||||||
match = re.match(route, url.path)
|
|
||||||
if match:
|
|
||||||
log.debug('Route "%s" matched "%s"', route, url.path)
|
|
||||||
args = []
|
|
||||||
for param in match.groups():
|
|
||||||
args.append(param)
|
|
||||||
response = func(*args)
|
|
||||||
break
|
|
||||||
if response:
|
|
||||||
self.send_response(response)
|
|
||||||
else:
|
|
||||||
self.send_response(HttpResponse(code='404 Not Found'))
|
|
||||||
self.close()
|
|
||||||
|
|
||||||
def serve_file(self, filename=None):
|
def serve_file(self, filename=None):
|
||||||
"""
|
"""
|
||||||
Send a file to the socket. For now, just a subset of file types
|
Send a file to the socket. For now, just a subset of file types
|
||||||
|
@ -329,9 +371,9 @@ class HttpConnection(object):
|
||||||
filename = u'index.html'
|
filename = u'index.html'
|
||||||
elif filename == u'stage':
|
elif filename == u'stage':
|
||||||
filename = u'stage.html'
|
filename = u'stage.html'
|
||||||
path = os.path.normpath(os.path.join(self.parent.html_dir, filename))
|
path = os.path.normpath(os.path.join(self.html_dir, filename))
|
||||||
if not path.startswith(self.parent.html_dir):
|
if not path.startswith(self.html_dir):
|
||||||
return HttpResponse(code=u'404 Not Found')
|
return self._http_not_found()
|
||||||
ext = os.path.splitext(filename)[1]
|
ext = os.path.splitext(filename)[1]
|
||||||
html = None
|
html = None
|
||||||
if ext == u'.html':
|
if ext == u'.html':
|
||||||
|
@ -360,11 +402,12 @@ class HttpConnection(object):
|
||||||
content = file_handle.read()
|
content = file_handle.read()
|
||||||
except IOError:
|
except IOError:
|
||||||
log.exception(u'Failed to open %s' % path)
|
log.exception(u'Failed to open %s' % path)
|
||||||
return HttpResponse(code=u'404 Not Found')
|
return self._http_not_found()
|
||||||
finally:
|
finally:
|
||||||
if file_handle:
|
if file_handle:
|
||||||
file_handle.close()
|
file_handle.close()
|
||||||
return HttpResponse(content, {u'Content-Type': mimetype})
|
cherrypy.response.headers['Content-Type'] = mimetype
|
||||||
|
return content
|
||||||
|
|
||||||
def poll(self):
|
def poll(self):
|
||||||
"""
|
"""
|
||||||
|
@ -379,18 +422,20 @@ class HttpConnection(object):
|
||||||
u'theme': self.live_controller.theme_screen.isChecked(),
|
u'theme': self.live_controller.theme_screen.isChecked(),
|
||||||
u'display': self.live_controller.desktop_screen.isChecked()
|
u'display': self.live_controller.desktop_screen.isChecked()
|
||||||
}
|
}
|
||||||
return HttpResponse(json.dumps({u'results': result}), {u'Content-Type': u'application/json'})
|
cherrypy.response.headers['Content-Type'] = u'application/json'
|
||||||
|
return json.dumps({u'results': result})
|
||||||
|
|
||||||
def display(self, action):
|
def display(self, action):
|
||||||
"""
|
"""
|
||||||
Hide or show the display screen.
|
Hide or show the display screen.
|
||||||
|
This is a cross Thread call and UI is updated so Events need to be used.
|
||||||
|
|
||||||
``action``
|
``action``
|
||||||
This is the action, either ``hide`` or ``show``.
|
This is the action, either ``hide`` or ``show``.
|
||||||
"""
|
"""
|
||||||
Registry().execute(u'slidecontroller_toggle_display', action)
|
self.live_controller.emit(QtCore.SIGNAL(u'slidecontroller_toggle_display'), action)
|
||||||
return HttpResponse(json.dumps({u'results': {u'success': True}}),
|
cherrypy.response.headers['Content-Type'] = u'application/json'
|
||||||
{u'Content-Type': u'application/json'})
|
return json.dumps({u'results': {u'success': True}})
|
||||||
|
|
||||||
def alert(self):
|
def alert(self):
|
||||||
"""
|
"""
|
||||||
|
@ -399,16 +444,16 @@ class HttpConnection(object):
|
||||||
plugin = self.plugin_manager.get_plugin_by_name("alerts")
|
plugin = self.plugin_manager.get_plugin_by_name("alerts")
|
||||||
if plugin.status == PluginStatus.Active:
|
if plugin.status == PluginStatus.Active:
|
||||||
try:
|
try:
|
||||||
text = json.loads(self.url_params[u'data'][0])[u'request'][u'text']
|
text = json.loads(self.request_data)[u'request'][u'text']
|
||||||
except KeyError, ValueError:
|
except KeyError, ValueError:
|
||||||
return HttpResponse(code=u'400 Bad Request')
|
return self._http_bad_request()
|
||||||
text = urllib.unquote(text)
|
text = urllib.unquote(text)
|
||||||
Registry().execute(u'alerts_text', [text])
|
self.alerts_manager.emit(QtCore.SIGNAL(u'alerts_text'), [text])
|
||||||
success = True
|
success = True
|
||||||
else:
|
else:
|
||||||
success = False
|
success = False
|
||||||
return HttpResponse(json.dumps({u'results': {u'success': success}}),
|
cherrypy.response.headers['Content-Type'] = u'application/json'
|
||||||
{u'Content-Type': u'application/json'})
|
return json.dumps({u'results': {u'success': success}})
|
||||||
|
|
||||||
def controller(self, display_type, action):
|
def controller(self, display_type, action):
|
||||||
"""
|
"""
|
||||||
|
@ -444,44 +489,44 @@ class HttpConnection(object):
|
||||||
if current_item:
|
if current_item:
|
||||||
json_data[u'results'][u'item'] = self.live_controller.service_item.unique_identifier
|
json_data[u'results'][u'item'] = self.live_controller.service_item.unique_identifier
|
||||||
else:
|
else:
|
||||||
if self.url_params and self.url_params.get(u'data'):
|
if self.request_data:
|
||||||
try:
|
try:
|
||||||
data = json.loads(self.url_params[u'data'][0])
|
data = json.loads(self.request_data)[u'request'][u'id']
|
||||||
except KeyError, ValueError:
|
except KeyError, ValueError:
|
||||||
return HttpResponse(code=u'400 Bad Request')
|
return self._http_bad_request()
|
||||||
log.info(data)
|
log.info(data)
|
||||||
# This slot expects an int within a list.
|
# This slot expects an int within a list.
|
||||||
id = data[u'request'][u'id']
|
self.live_controller.emit(QtCore.SIGNAL(event), [data])
|
||||||
Registry().execute(event, [id])
|
|
||||||
else:
|
else:
|
||||||
Registry().execute(event)
|
self.live_controller.emit(QtCore.SIGNAL(event))
|
||||||
json_data = {u'results': {u'success': True}}
|
json_data = {u'results': {u'success': True}}
|
||||||
return HttpResponse(json.dumps(json_data), {u'Content-Type': u'application/json'})
|
cherrypy.response.headers['Content-Type'] = u'application/json'
|
||||||
|
return json.dumps(json_data)
|
||||||
|
|
||||||
def service(self, action):
|
def service(self, action):
|
||||||
"""
|
"""
|
||||||
Handles requests for service items
|
Handles requests for service items in the service manager
|
||||||
|
|
||||||
``action``
|
``action``
|
||||||
The action to perform.
|
The action to perform.
|
||||||
"""
|
"""
|
||||||
event = u'servicemanager_%s' % action
|
event = u'servicemanager_%s' % action
|
||||||
if action == u'list':
|
if action == u'list':
|
||||||
return HttpResponse(json.dumps({u'results': {u'items': self._get_service_items()}}),
|
cherrypy.response.headers['Content-Type'] = u'application/json'
|
||||||
{u'Content-Type': u'application/json'})
|
return json.dumps({u'results': {u'items': self._get_service_items()}})
|
||||||
else:
|
event += u'_item'
|
||||||
event += u'_item'
|
if self.request_data:
|
||||||
if self.url_params and self.url_params.get(u'data'):
|
|
||||||
try:
|
try:
|
||||||
data = json.loads(self.url_params[u'data'][0])
|
data = json.loads(self.request_data)[u'request'][u'id']
|
||||||
except KeyError, ValueError:
|
except KeyError:
|
||||||
return HttpResponse(code=u'400 Bad Request')
|
return self._http_bad_request()
|
||||||
Registry().execute(event, data[u'request'][u'id'])
|
self.service_manager.emit(QtCore.SIGNAL(event), data)
|
||||||
else:
|
else:
|
||||||
Registry().execute(event)
|
Registry().execute(event)
|
||||||
return HttpResponse(json.dumps({u'results': {u'success': True}}), {u'Content-Type': u'application/json'})
|
cherrypy.response.headers['Content-Type'] = u'application/json'
|
||||||
|
return json.dumps({u'results': {u'success': True}})
|
||||||
|
|
||||||
def pluginInfo(self, action):
|
def plugin_info(self, action):
|
||||||
"""
|
"""
|
||||||
Return plugin related information, based on the action.
|
Return plugin related information, based on the action.
|
||||||
|
|
||||||
|
@ -493,8 +538,9 @@ class HttpConnection(object):
|
||||||
searches = []
|
searches = []
|
||||||
for plugin in self.plugin_manager.plugins:
|
for plugin in self.plugin_manager.plugins:
|
||||||
if plugin.status == PluginStatus.Active and plugin.media_item and plugin.media_item.has_search:
|
if plugin.status == PluginStatus.Active and plugin.media_item and plugin.media_item.has_search:
|
||||||
searches.append([plugin.name, unicode(plugin.textStrings[StringContent.Name][u'plural'])])
|
searches.append([plugin.name, unicode(plugin.text_strings[StringContent.Name][u'plural'])])
|
||||||
return HttpResponse(json.dumps({u'results': {u'items': searches}}), {u'Content-Type': u'application/json'})
|
cherrypy.response.headers['Content-Type'] = u'application/json'
|
||||||
|
return json.dumps({u'results': {u'items': searches}})
|
||||||
|
|
||||||
def search(self, plugin_name):
|
def search(self, plugin_name):
|
||||||
"""
|
"""
|
||||||
|
@ -504,69 +550,63 @@ class HttpConnection(object):
|
||||||
The plugin name to search in.
|
The plugin name to search in.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
text = json.loads(self.url_params[u'data'][0])[u'request'][u'text']
|
text = json.loads(self.request_data)[u'request'][u'text']
|
||||||
except KeyError, ValueError:
|
except KeyError, ValueError:
|
||||||
return HttpResponse(code=u'400 Bad Request')
|
return self._http_bad_request()
|
||||||
text = urllib.unquote(text)
|
text = urllib.unquote(text)
|
||||||
plugin = self.plugin_manager.get_plugin_by_name(plugin_name)
|
plugin = self.plugin_manager.get_plugin_by_name(plugin_name)
|
||||||
if plugin.status == PluginStatus.Active and plugin.media_item and plugin.media_item.has_search:
|
if plugin.status == PluginStatus.Active and plugin.media_item and plugin.media_item.has_search:
|
||||||
results = plugin.media_item.search(text, False)
|
results = plugin.media_item.search(text, False)
|
||||||
else:
|
else:
|
||||||
results = []
|
results = []
|
||||||
return HttpResponse(json.dumps({u'results': {u'items': results}}), {u'Content-Type': u'application/json'})
|
cherrypy.response.headers['Content-Type'] = u'application/json'
|
||||||
|
return json.dumps({u'results': {u'items': results}})
|
||||||
|
|
||||||
def go_live(self, plugin_name):
|
def go_live(self, plugin_name):
|
||||||
"""
|
"""
|
||||||
Go live on an item of type ``plugin``.
|
Go live on an item of type ``plugin``.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
id = json.loads(self.url_params[u'data'][0])[u'request'][u'id']
|
id = json.loads(self.request_data)[u'request'][u'id']
|
||||||
except KeyError, ValueError:
|
except KeyError, ValueError:
|
||||||
return HttpResponse(code=u'400 Bad Request')
|
return self._http_bad_request()
|
||||||
plugin = self.plugin_manager.get_plugin_by_name(plugin_name)
|
plugin = self.plugin_manager.get_plugin_by_name(plugin_name)
|
||||||
if plugin.status == PluginStatus.Active and plugin.media_item:
|
if plugin.status == PluginStatus.Active and plugin.media_item:
|
||||||
plugin.media_item.go_live(id, remote=True)
|
plugin.media_item.emit(QtCore.SIGNAL(u'%s_go_live' % plugin_name), [id, True])
|
||||||
return HttpResponse(code=u'200 OK')
|
return self._http_success()
|
||||||
|
|
||||||
def add_to_service(self, plugin_name):
|
def add_to_service(self, plugin_name):
|
||||||
"""
|
"""
|
||||||
Add item of type ``plugin_name`` to the end of the service.
|
Add item of type ``plugin_name`` to the end of the service.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
id = json.loads(self.url_params[u'data'][0])[u'request'][u'id']
|
id = json.loads(self.request_data)[u'request'][u'id']
|
||||||
except KeyError, ValueError:
|
except KeyError, ValueError:
|
||||||
return HttpResponse(code=u'400 Bad Request')
|
return self._http_bad_request()
|
||||||
plugin = self.plugin_manager.get_plugin_by_name(plugin_name)
|
plugin = self.plugin_manager.get_plugin_by_name(plugin_name)
|
||||||
if plugin.status == PluginStatus.Active and plugin.media_item:
|
if plugin.status == PluginStatus.Active and plugin.media_item:
|
||||||
item_id = plugin.media_item.createItemFromId(id)
|
item_id = plugin.media_item.create_item_from_id(id)
|
||||||
plugin.media_item.add_to_service(item_id, remote=True)
|
plugin.media_item.emit(QtCore.SIGNAL(u'%s_add_to_service' % plugin_name), [item_id, True])
|
||||||
return HttpResponse(code=u'200 OK')
|
self._http_success()
|
||||||
|
|
||||||
def send_response(self, response):
|
def _http_success(self):
|
||||||
http = u'HTTP/1.1 %s\r\n' % response.code
|
"""
|
||||||
for header, value in response.headers.iteritems():
|
Set the HTTP success return code.
|
||||||
http += '%s: %s\r\n' % (header, value)
|
"""
|
||||||
http += '\r\n'
|
cherrypy.response.status = 200
|
||||||
self.socket.write(http)
|
|
||||||
self.socket.write(response.content)
|
|
||||||
|
|
||||||
def disconnected(self):
|
def _http_bad_request(self):
|
||||||
"""
|
"""
|
||||||
The client has disconnected. Tidy up
|
Set the HTTP bad response return code.
|
||||||
"""
|
"""
|
||||||
log.debug(u'socket disconnected')
|
cherrypy.response.status = 400
|
||||||
self.close()
|
|
||||||
|
|
||||||
def close(self):
|
def _http_not_found(self):
|
||||||
"""
|
"""
|
||||||
The server has closed the connection. Tidy up
|
Set the HTTP not found return code.
|
||||||
"""
|
"""
|
||||||
if not self.socket:
|
cherrypy.response.status = 404
|
||||||
return
|
cherrypy.response.body = ["<html><body>Sorry, an error occurred </body></html>"]
|
||||||
log.debug(u'close socket')
|
|
||||||
self.socket.close()
|
|
||||||
self.socket = None
|
|
||||||
self.parent.close_connection(self)
|
|
||||||
|
|
||||||
def _get_service_manager(self):
|
def _get_service_manager(self):
|
||||||
"""
|
"""
|
||||||
|
@ -597,3 +637,13 @@ class HttpConnection(object):
|
||||||
return self._plugin_manager
|
return self._plugin_manager
|
||||||
|
|
||||||
plugin_manager = property(_get_plugin_manager)
|
plugin_manager = property(_get_plugin_manager)
|
||||||
|
|
||||||
|
def _get_alerts_manager(self):
|
||||||
|
"""
|
||||||
|
Adds the alerts manager to the class dynamically
|
||||||
|
"""
|
||||||
|
if not hasattr(self, u'_alerts_manager'):
|
||||||
|
self._alerts_manager = Registry().get(u'alerts_manager')
|
||||||
|
return self._alerts_manager
|
||||||
|
|
||||||
|
alerts_manager = property(_get_alerts_manager)
|
||||||
|
|
|
@ -27,9 +27,12 @@
|
||||||
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
|
||||||
|
import os.path
|
||||||
|
|
||||||
from PyQt4 import QtCore, QtGui, QtNetwork
|
from PyQt4 import QtCore, QtGui, QtNetwork
|
||||||
|
|
||||||
from openlp.core.lib import Registry, Settings, SettingsTab, translate
|
from openlp.core.lib import Settings, SettingsTab, translate
|
||||||
|
from openlp.core.utils import AppLocation
|
||||||
|
|
||||||
|
|
||||||
ZERO_URL = u'0.0.0.0'
|
ZERO_URL = u'0.0.0.0'
|
||||||
|
@ -53,32 +56,84 @@ class RemoteTab(SettingsTab):
|
||||||
self.address_label.setObjectName(u'address_label')
|
self.address_label.setObjectName(u'address_label')
|
||||||
self.address_edit = QtGui.QLineEdit(self.server_settings_group_box)
|
self.address_edit = QtGui.QLineEdit(self.server_settings_group_box)
|
||||||
self.address_edit.setSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Fixed)
|
self.address_edit.setSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Fixed)
|
||||||
self.address_edit.setValidator(QtGui.QRegExpValidator(QtCore.QRegExp(
|
self.address_edit.setValidator(QtGui.QRegExpValidator(QtCore.QRegExp(u'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}'),
|
||||||
u'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}'), self))
|
self))
|
||||||
self.address_edit.setObjectName(u'address_edit')
|
self.address_edit.setObjectName(u'address_edit')
|
||||||
self.server_settings_layout.addRow(self.address_label, self.address_edit)
|
self.server_settings_layout.addRow(self.address_label, self.address_edit)
|
||||||
self.twelve_hour_check_box = QtGui.QCheckBox(self.server_settings_group_box)
|
self.twelve_hour_check_box = QtGui.QCheckBox(self.server_settings_group_box)
|
||||||
self.twelve_hour_check_box.setObjectName(u'twelve_hour_check_box')
|
self.twelve_hour_check_box.setObjectName(u'twelve_hour_check_box')
|
||||||
self.server_settings_layout.addRow(self.twelve_hour_check_box)
|
self.server_settings_layout.addRow(self.twelve_hour_check_box)
|
||||||
self.port_label = QtGui.QLabel(self.server_settings_group_box)
|
self.left_layout.addWidget(self.server_settings_group_box)
|
||||||
|
self.http_settings_group_box = QtGui.QGroupBox(self.left_column)
|
||||||
|
self.http_settings_group_box.setObjectName(u'http_settings_group_box')
|
||||||
|
self.http_setting_layout = QtGui.QFormLayout(self.http_settings_group_box)
|
||||||
|
self.http_setting_layout.setObjectName(u'http_setting_layout')
|
||||||
|
self.port_label = QtGui.QLabel(self.http_settings_group_box)
|
||||||
self.port_label.setObjectName(u'port_label')
|
self.port_label.setObjectName(u'port_label')
|
||||||
self.port_spin_box = QtGui.QSpinBox(self.server_settings_group_box)
|
self.port_spin_box = QtGui.QSpinBox(self.http_settings_group_box)
|
||||||
self.port_spin_box.setMaximum(32767)
|
self.port_spin_box.setMaximum(32767)
|
||||||
self.port_spin_box.setObjectName(u'port_spin_box')
|
self.port_spin_box.setObjectName(u'port_spin_box')
|
||||||
self.server_settings_layout.addRow(self.port_label, self.port_spin_box)
|
self.http_setting_layout.addRow(self.port_label, self.port_spin_box)
|
||||||
self.remote_url_label = QtGui.QLabel(self.server_settings_group_box)
|
self.remote_url_label = QtGui.QLabel(self.http_settings_group_box)
|
||||||
self.remote_url_label.setObjectName(u'remote_url_label')
|
self.remote_url_label.setObjectName(u'remote_url_label')
|
||||||
self.remote_url = QtGui.QLabel(self.server_settings_group_box)
|
self.remote_url = QtGui.QLabel(self.http_settings_group_box)
|
||||||
self.remote_url.setObjectName(u'remote_url')
|
self.remote_url.setObjectName(u'remote_url')
|
||||||
self.remote_url.setOpenExternalLinks(True)
|
self.remote_url.setOpenExternalLinks(True)
|
||||||
self.server_settings_layout.addRow(self.remote_url_label, self.remote_url)
|
self.http_setting_layout.addRow(self.remote_url_label, self.remote_url)
|
||||||
self.stage_url_label = QtGui.QLabel(self.server_settings_group_box)
|
self.stage_url_label = QtGui.QLabel(self.http_settings_group_box)
|
||||||
self.stage_url_label.setObjectName(u'stage_url_label')
|
self.stage_url_label.setObjectName(u'stage_url_label')
|
||||||
self.stage_url = QtGui.QLabel(self.server_settings_group_box)
|
self.stage_url = QtGui.QLabel(self.http_settings_group_box)
|
||||||
self.stage_url.setObjectName(u'stage_url')
|
self.stage_url.setObjectName(u'stage_url')
|
||||||
self.stage_url.setOpenExternalLinks(True)
|
self.stage_url.setOpenExternalLinks(True)
|
||||||
self.server_settings_layout.addRow(self.stage_url_label, self.stage_url)
|
self.http_setting_layout.addRow(self.stage_url_label, self.stage_url)
|
||||||
self.left_layout.addWidget(self.server_settings_group_box)
|
self.left_layout.addWidget(self.http_settings_group_box)
|
||||||
|
self.https_settings_group_box = QtGui.QGroupBox(self.left_column)
|
||||||
|
self.https_settings_group_box.setCheckable(True)
|
||||||
|
self.https_settings_group_box.setChecked(False)
|
||||||
|
self.https_settings_group_box.setObjectName(u'https_settings_group_box')
|
||||||
|
self.https_settings_layout = QtGui.QFormLayout(self.https_settings_group_box)
|
||||||
|
self.https_settings_layout.setObjectName(u'https_settings_layout')
|
||||||
|
self.https_error_label = QtGui.QLabel(self.https_settings_group_box)
|
||||||
|
self.https_error_label.setVisible(False)
|
||||||
|
self.https_error_label.setWordWrap(True)
|
||||||
|
self.https_error_label.setObjectName(u'https_error_label')
|
||||||
|
self.https_settings_layout.addRow(self.https_error_label)
|
||||||
|
self.https_port_label = QtGui.QLabel(self.https_settings_group_box)
|
||||||
|
self.https_port_label.setObjectName(u'https_port_label')
|
||||||
|
self.https_port_spin_box = QtGui.QSpinBox(self.https_settings_group_box)
|
||||||
|
self.https_port_spin_box.setMaximum(32767)
|
||||||
|
self.https_port_spin_box.setObjectName(u'https_port_spin_box')
|
||||||
|
self.https_settings_layout.addRow(self.https_port_label, self.https_port_spin_box)
|
||||||
|
self.remote_https_url = QtGui.QLabel(self.https_settings_group_box)
|
||||||
|
self.remote_https_url.setObjectName(u'remote_http_url')
|
||||||
|
self.remote_https_url.setOpenExternalLinks(True)
|
||||||
|
self.remote_https_url_label = QtGui.QLabel(self.https_settings_group_box)
|
||||||
|
self.remote_https_url_label.setObjectName(u'remote_http_url_label')
|
||||||
|
self.https_settings_layout.addRow(self.remote_https_url_label, self.remote_https_url)
|
||||||
|
self.stage_https_url_label = QtGui.QLabel(self.http_settings_group_box)
|
||||||
|
self.stage_https_url_label.setObjectName(u'stage_https_url_label')
|
||||||
|
self.stage_https_url = QtGui.QLabel(self.https_settings_group_box)
|
||||||
|
self.stage_https_url.setObjectName(u'stage_https_url')
|
||||||
|
self.stage_https_url.setOpenExternalLinks(True)
|
||||||
|
self.https_settings_layout.addRow(self.stage_https_url_label, self.stage_https_url)
|
||||||
|
self.left_layout.addWidget(self.https_settings_group_box)
|
||||||
|
self.user_login_group_box = QtGui.QGroupBox(self.left_column)
|
||||||
|
self.user_login_group_box.setCheckable(True)
|
||||||
|
self.user_login_group_box.setChecked(False)
|
||||||
|
self.user_login_group_box.setObjectName(u'user_login_group_box')
|
||||||
|
self.user_login_layout = QtGui.QFormLayout(self.user_login_group_box)
|
||||||
|
self.user_login_layout.setObjectName(u'user_login_layout')
|
||||||
|
self.user_id_label = QtGui.QLabel(self.user_login_group_box)
|
||||||
|
self.user_id_label.setObjectName(u'user_id_label')
|
||||||
|
self.user_id = QtGui.QLineEdit(self.user_login_group_box)
|
||||||
|
self.user_id.setObjectName(u'user_id')
|
||||||
|
self.user_login_layout.addRow(self.user_id_label, self.user_id)
|
||||||
|
self.password_label = QtGui.QLabel(self.user_login_group_box)
|
||||||
|
self.password_label.setObjectName(u'password_label')
|
||||||
|
self.password = QtGui.QLineEdit(self.user_login_group_box)
|
||||||
|
self.password.setObjectName(u'password')
|
||||||
|
self.user_login_layout.addRow(self.password_label, self.password)
|
||||||
|
self.left_layout.addWidget(self.user_login_group_box)
|
||||||
self.android_app_group_box = QtGui.QGroupBox(self.right_column)
|
self.android_app_group_box = QtGui.QGroupBox(self.right_column)
|
||||||
self.android_app_group_box.setObjectName(u'android_app_group_box')
|
self.android_app_group_box.setObjectName(u'android_app_group_box')
|
||||||
self.right_layout.addWidget(self.android_app_group_box)
|
self.right_layout.addWidget(self.android_app_group_box)
|
||||||
|
@ -96,9 +151,11 @@ class RemoteTab(SettingsTab):
|
||||||
self.qr_layout.addWidget(self.qr_description_label)
|
self.qr_layout.addWidget(self.qr_description_label)
|
||||||
self.left_layout.addStretch()
|
self.left_layout.addStretch()
|
||||||
self.right_layout.addStretch()
|
self.right_layout.addStretch()
|
||||||
self.twelve_hour_check_box.stateChanged.connect(self.onTwelveHourCheckBoxChanged)
|
self.twelve_hour_check_box.stateChanged.connect(self.on_twelve_hour_check_box_changed)
|
||||||
self.address_edit.textChanged.connect(self.set_urls)
|
self.address_edit.textChanged.connect(self.set_urls)
|
||||||
self.port_spin_box.valueChanged.connect(self.set_urls)
|
self.port_spin_box.valueChanged.connect(self.set_urls)
|
||||||
|
self.https_port_spin_box.valueChanged.connect(self.set_urls)
|
||||||
|
self.https_settings_group_box.clicked.connect(self.https_changed)
|
||||||
|
|
||||||
def retranslateUi(self):
|
def retranslateUi(self):
|
||||||
self.server_settings_group_box.setTitle(translate('RemotePlugin.RemoteTab', 'Server Settings'))
|
self.server_settings_group_box.setTitle(translate('RemotePlugin.RemoteTab', 'Server Settings'))
|
||||||
|
@ -112,8 +169,21 @@ class RemoteTab(SettingsTab):
|
||||||
'Scan the QR code or click <a href="https://play.google.com/store/'
|
'Scan the QR code or click <a href="https://play.google.com/store/'
|
||||||
'apps/details?id=org.openlp.android">download</a> to install the '
|
'apps/details?id=org.openlp.android">download</a> to install the '
|
||||||
'Android app from Google Play.'))
|
'Android app from Google Play.'))
|
||||||
|
self.https_settings_group_box.setTitle(translate('RemotePlugin.RemoteTab', 'HTTPS Server'))
|
||||||
|
self.https_error_label.setText(translate('RemotePlugin.RemoteTab',
|
||||||
|
'Could not find an SSL certificate. The HTTPS server will not be available unless an SSL certificate '
|
||||||
|
'is found. Please see the manual for more information.'))
|
||||||
|
self.https_port_label.setText(self.port_label.text())
|
||||||
|
self.remote_https_url_label.setText(self.remote_url_label.text())
|
||||||
|
self.stage_https_url_label.setText(self.stage_url_label.text())
|
||||||
|
self.user_login_group_box.setTitle(translate('RemotePlugin.RemoteTab', 'User Authentication'))
|
||||||
|
self.user_id_label.setText(translate('RemotePlugin.RemoteTab', 'User id:'))
|
||||||
|
self.password_label.setText(translate('RemotePlugin.RemoteTab', 'Password:'))
|
||||||
|
|
||||||
def set_urls(self):
|
def set_urls(self):
|
||||||
|
"""
|
||||||
|
Update the display based on the data input on the screen
|
||||||
|
"""
|
||||||
ip_address = u'localhost'
|
ip_address = u'localhost'
|
||||||
if self.address_edit.text() == ZERO_URL:
|
if self.address_edit.text() == ZERO_URL:
|
||||||
interfaces = QtNetwork.QNetworkInterface.allInterfaces()
|
interfaces = QtNetwork.QNetworkInterface.allInterfaces()
|
||||||
|
@ -129,31 +199,73 @@ class RemoteTab(SettingsTab):
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
ip_address = self.address_edit.text()
|
ip_address = self.address_edit.text()
|
||||||
url = u'http://%s:%s/' % (ip_address, self.port_spin_box.value())
|
http_url = u'http://%s:%s/' % (ip_address, self.port_spin_box.value())
|
||||||
self.remote_url.setText(u'<a href="%s">%s</a>' % (url, url))
|
https_url = u'https://%s:%s/' % (ip_address, self.https_port_spin_box.value())
|
||||||
url += u'stage'
|
self.remote_url.setText(u'<a href="%s">%s</a>' % (http_url, http_url))
|
||||||
self.stage_url.setText(u'<a href="%s">%s</a>' % (url, url))
|
self.remote_https_url.setText(u'<a href="%s">%s</a>' % (https_url, https_url))
|
||||||
|
http_url += u'stage'
|
||||||
|
https_url += u'stage'
|
||||||
|
self.stage_url.setText(u'<a href="%s">%s</a>' % (http_url, http_url))
|
||||||
|
self.stage_https_url.setText(u'<a href="%s">%s</a>' % (https_url, https_url))
|
||||||
|
|
||||||
def load(self):
|
def load(self):
|
||||||
|
"""
|
||||||
|
Load the configuration and update the server configuration if necessary
|
||||||
|
"""
|
||||||
self.port_spin_box.setValue(Settings().value(self.settings_section + u'/port'))
|
self.port_spin_box.setValue(Settings().value(self.settings_section + u'/port'))
|
||||||
|
self.https_port_spin_box.setValue(Settings().value(self.settings_section + u'/https port'))
|
||||||
self.address_edit.setText(Settings().value(self.settings_section + u'/ip address'))
|
self.address_edit.setText(Settings().value(self.settings_section + u'/ip address'))
|
||||||
self.twelve_hour = Settings().value(self.settings_section + u'/twelve hour')
|
self.twelve_hour = Settings().value(self.settings_section + u'/twelve hour')
|
||||||
self.twelve_hour_check_box.setChecked(self.twelve_hour)
|
self.twelve_hour_check_box.setChecked(self.twelve_hour)
|
||||||
|
local_data = AppLocation.get_directory(AppLocation.DataDir)
|
||||||
|
if not os.path.exists(os.path.join(local_data, u'remotes', u'openlp.crt')) or \
|
||||||
|
not os.path.exists(os.path.join(local_data, u'remotes', u'openlp.key')):
|
||||||
|
self.https_settings_group_box.setChecked(False)
|
||||||
|
self.https_settings_group_box.setEnabled(False)
|
||||||
|
self.https_error_label.setVisible(True)
|
||||||
|
else:
|
||||||
|
self.https_settings_group_box.setChecked(Settings().value(self.settings_section + u'/https enabled'))
|
||||||
|
self.https_settings_group_box.setEnabled(True)
|
||||||
|
self.https_error_label.setVisible(False)
|
||||||
|
self.user_login_group_box.setChecked(Settings().value(self.settings_section + u'/authentication enabled'))
|
||||||
|
self.user_id.setText(Settings().value(self.settings_section + u'/user id'))
|
||||||
|
self.password.setText(Settings().value(self.settings_section + u'/password'))
|
||||||
self.set_urls()
|
self.set_urls()
|
||||||
|
self.https_changed()
|
||||||
|
|
||||||
def save(self):
|
def save(self):
|
||||||
changed = False
|
"""
|
||||||
|
Save the configuration and update the server configuration if necessary
|
||||||
|
"""
|
||||||
if Settings().value(self.settings_section + u'/ip address') != self.address_edit.text() or \
|
if Settings().value(self.settings_section + u'/ip address') != self.address_edit.text() or \
|
||||||
Settings().value(self.settings_section + u'/port') != self.port_spin_box.value():
|
Settings().value(self.settings_section + u'/port') != self.port_spin_box.value() or \
|
||||||
changed = True
|
Settings().value(self.settings_section + u'/https port') != self.https_port_spin_box.value() or \
|
||||||
|
Settings().value(self.settings_section + u'/https enabled') != \
|
||||||
|
self.https_settings_group_box.isChecked() or \
|
||||||
|
Settings().value(self.settings_section + u'/authentication enabled') != \
|
||||||
|
self.user_login_group_box.isChecked():
|
||||||
|
self.settings_form.register_post_process(u'remotes_config_updated')
|
||||||
Settings().setValue(self.settings_section + u'/port', self.port_spin_box.value())
|
Settings().setValue(self.settings_section + u'/port', self.port_spin_box.value())
|
||||||
|
Settings().setValue(self.settings_section + u'/https port', self.https_port_spin_box.value())
|
||||||
|
Settings().setValue(self.settings_section + u'/https enabled', self.https_settings_group_box.isChecked())
|
||||||
Settings().setValue(self.settings_section + u'/ip address', self.address_edit.text())
|
Settings().setValue(self.settings_section + u'/ip address', self.address_edit.text())
|
||||||
Settings().setValue(self.settings_section + u'/twelve hour', self.twelve_hour)
|
Settings().setValue(self.settings_section + u'/twelve hour', self.twelve_hour)
|
||||||
if changed:
|
Settings().setValue(self.settings_section + u'/authentication enabled', self.user_login_group_box.isChecked())
|
||||||
Registry().execute(u'remotes_config_updated')
|
Settings().setValue(self.settings_section + u'/user id', self.user_id.text())
|
||||||
|
Settings().setValue(self.settings_section + u'/password', self.password.text())
|
||||||
|
|
||||||
def onTwelveHourCheckBoxChanged(self, check_state):
|
def on_twelve_hour_check_box_changed(self, check_state):
|
||||||
|
"""
|
||||||
|
Toggle the 12 hour check box.
|
||||||
|
"""
|
||||||
self.twelve_hour = False
|
self.twelve_hour = False
|
||||||
# we have a set value convert to True/False
|
# we have a set value convert to True/False
|
||||||
if check_state == QtCore.Qt.Checked:
|
if check_state == QtCore.Qt.Checked:
|
||||||
self.twelve_hour = True
|
self.twelve_hour = True
|
||||||
|
|
||||||
|
def https_changed(self):
|
||||||
|
"""
|
||||||
|
Invert the HTTP group box based on Https group settings
|
||||||
|
"""
|
||||||
|
self.http_settings_group_box.setEnabled(not self.https_settings_group_box.isChecked())
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,8 @@
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
from PyQt4 import QtGui
|
||||||
|
|
||||||
from openlp.core.lib import Plugin, StringContent, translate, build_icon
|
from openlp.core.lib import Plugin, StringContent, translate, build_icon
|
||||||
from openlp.plugins.remotes.lib import RemoteTab, HttpServer
|
from openlp.plugins.remotes.lib import RemoteTab, HttpServer
|
||||||
|
|
||||||
|
@ -37,6 +39,11 @@ log = logging.getLogger(__name__)
|
||||||
__default_settings__ = {
|
__default_settings__ = {
|
||||||
u'remotes/twelve hour': True,
|
u'remotes/twelve hour': True,
|
||||||
u'remotes/port': 4316,
|
u'remotes/port': 4316,
|
||||||
|
u'remotes/https port': 4317,
|
||||||
|
u'remotes/https enabled': False,
|
||||||
|
u'remotes/user id': u'openlp',
|
||||||
|
u'remotes/password': u'password',
|
||||||
|
u'remotes/authentication enabled': False,
|
||||||
u'remotes/ip address': u'0.0.0.0'
|
u'remotes/ip address': u'0.0.0.0'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,7 +67,8 @@ class RemotesPlugin(Plugin):
|
||||||
"""
|
"""
|
||||||
log.debug(u'initialise')
|
log.debug(u'initialise')
|
||||||
Plugin.initialise(self)
|
Plugin.initialise(self)
|
||||||
self.server = HttpServer(self)
|
self.server = HttpServer()
|
||||||
|
self.server.start_server()
|
||||||
|
|
||||||
def finalise(self):
|
def finalise(self):
|
||||||
"""
|
"""
|
||||||
|
@ -70,6 +78,7 @@ class RemotesPlugin(Plugin):
|
||||||
Plugin.finalise(self)
|
Plugin.finalise(self)
|
||||||
if self.server:
|
if self.server:
|
||||||
self.server.close()
|
self.server.close()
|
||||||
|
self.server = None
|
||||||
|
|
||||||
def about(self):
|
def about(self):
|
||||||
"""
|
"""
|
||||||
|
@ -99,5 +108,6 @@ class RemotesPlugin(Plugin):
|
||||||
"""
|
"""
|
||||||
Called when Config is changed to restart the server on new address or port
|
Called when Config is changed to restart the server on new address or port
|
||||||
"""
|
"""
|
||||||
self.finalise()
|
log.debug(u'remote config changed')
|
||||||
self.initialise()
|
self.main_window.information_message(translate('RemotePlugin', 'Configuration Change'),
|
||||||
|
translate('RemotePlugin', 'OpenLP will need to be restarted for the Remote changes to become active.'))
|
||||||
|
|
|
@ -52,3 +52,4 @@ This allows OpenLP to use ``self.object`` for all the GUI elements while keeping
|
||||||
them separate from the functionality, so that it is easier to recreate the GUI
|
them separate from the functionality, so that it is easier to recreate the GUI
|
||||||
from the .ui files later if necessary.
|
from the .ui files later if necessary.
|
||||||
"""
|
"""
|
||||||
|
from editsongform import EditSongForm
|
||||||
|
|
|
@ -320,7 +320,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
|
||||||
for plugin in self.plugin_manager.plugins:
|
for plugin in self.plugin_manager.plugins:
|
||||||
if plugin.name == u'media' and plugin.status == PluginStatus.Active:
|
if plugin.name == u'media' and plugin.status == PluginStatus.Active:
|
||||||
self.from_media_button.setVisible(True)
|
self.from_media_button.setVisible(True)
|
||||||
self.media_form.populateFiles(plugin.media_item.getList(MediaType.Audio))
|
self.media_form.populateFiles(plugin.media_item.get_list(MediaType.Audio))
|
||||||
break
|
break
|
||||||
|
|
||||||
def new_song(self):
|
def new_song(self):
|
||||||
|
@ -714,7 +714,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
|
||||||
text = self.song_book_combo_box.currentText()
|
text = self.song_book_combo_box.currentText()
|
||||||
if item == 0 and text:
|
if item == 0 and text:
|
||||||
temp_song_book = text
|
temp_song_book = text
|
||||||
self.media_item.songMaintenanceForm.exec_(True)
|
self.media_item.song_maintenance_form.exec_(True)
|
||||||
self.load_authors()
|
self.load_authors()
|
||||||
self.load_books()
|
self.load_books()
|
||||||
self.load_topics()
|
self.load_topics()
|
||||||
|
|
|
@ -235,7 +235,7 @@ class SongExportForm(OpenLPWizard):
|
||||||
self.availableListWidget.addItem(item)
|
self.availableListWidget.addItem(item)
|
||||||
self.application.set_normal_cursor()
|
self.application.set_normal_cursor()
|
||||||
|
|
||||||
def preWizard(self):
|
def pre_wizard(self):
|
||||||
"""
|
"""
|
||||||
Perform pre export tasks.
|
Perform pre export tasks.
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -325,7 +325,7 @@ class SongImportForm(OpenLPWizard):
|
||||||
self.error_copy_to_button.setHidden(True)
|
self.error_copy_to_button.setHidden(True)
|
||||||
self.error_save_to_button.setHidden(True)
|
self.error_save_to_button.setHidden(True)
|
||||||
|
|
||||||
def preWizard(self):
|
def pre_wizard(self):
|
||||||
"""
|
"""
|
||||||
Perform pre import tasks
|
Perform pre import tasks
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -50,13 +50,11 @@ from sundayplusimport import SundayPlusImport
|
||||||
from foilpresenterimport import FoilPresenterImport
|
from foilpresenterimport import FoilPresenterImport
|
||||||
from zionworximport import ZionWorxImport
|
from zionworximport import ZionWorxImport
|
||||||
# Imports that might fail
|
# Imports that might fail
|
||||||
|
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
try:
|
|
||||||
from olp1import import OpenLP1SongImport
|
|
||||||
HAS_OPENLP1 = True
|
|
||||||
except ImportError:
|
|
||||||
log.exception('Error importing %s', 'OpenLP1SongImport')
|
|
||||||
HAS_OPENLP1 = False
|
|
||||||
try:
|
try:
|
||||||
from sofimport import SofImport
|
from sofimport import SofImport
|
||||||
HAS_SOF = True
|
HAS_SOF = True
|
||||||
|
@ -144,23 +142,22 @@ class SongFormat(object):
|
||||||
Unknown = -1
|
Unknown = -1
|
||||||
OpenLyrics = 0
|
OpenLyrics = 0
|
||||||
OpenLP2 = 1
|
OpenLP2 = 1
|
||||||
OpenLP1 = 2
|
Generic = 2
|
||||||
Generic = 3
|
CCLI = 3
|
||||||
CCLI = 4
|
DreamBeam = 4
|
||||||
DreamBeam = 5
|
EasySlides = 5
|
||||||
EasySlides = 6
|
EasyWorship = 6
|
||||||
EasyWorship = 7
|
FoilPresenter = 7
|
||||||
FoilPresenter = 8
|
MediaShout = 8
|
||||||
MediaShout = 9
|
OpenSong = 9
|
||||||
OpenSong = 10
|
PowerSong = 10
|
||||||
PowerSong = 11
|
SongBeamer = 11
|
||||||
SongBeamer = 12
|
SongPro = 12
|
||||||
SongPro = 13
|
SongShowPlus = 13
|
||||||
SongShowPlus = 14
|
SongsOfFellowship = 14
|
||||||
SongsOfFellowship = 15
|
SundayPlus = 15
|
||||||
SundayPlus = 16
|
WordsOfWorship = 16
|
||||||
WordsOfWorship = 17
|
ZionWorx = 17
|
||||||
ZionWorx = 18
|
|
||||||
|
|
||||||
# Set optional attribute defaults
|
# Set optional attribute defaults
|
||||||
__defaults__ = {
|
__defaults__ = {
|
||||||
|
@ -191,14 +188,6 @@ class SongFormat(object):
|
||||||
u'selectMode': SongFormatSelect.SingleFile,
|
u'selectMode': SongFormatSelect.SingleFile,
|
||||||
u'filter': u'%s (*.sqlite)' % (translate('SongsPlugin.ImportWizardForm', 'OpenLP 2.0 Databases'))
|
u'filter': u'%s (*.sqlite)' % (translate('SongsPlugin.ImportWizardForm', 'OpenLP 2.0 Databases'))
|
||||||
},
|
},
|
||||||
OpenLP1: {
|
|
||||||
u'name': UiStrings().OLPV1,
|
|
||||||
u'prefix': u'openLP1',
|
|
||||||
u'canDisable': True,
|
|
||||||
u'selectMode': SongFormatSelect.SingleFile,
|
|
||||||
u'filter': u'%s (*.olp)' % translate('SongsPlugin.ImportWizardForm', 'openlp.org v1.x Databases'),
|
|
||||||
u'disabledLabelText': WizardStrings.NoSqlite
|
|
||||||
},
|
|
||||||
Generic: {
|
Generic: {
|
||||||
u'name': translate('SongsPlugin.ImportWizardForm', 'Generic Document/Presentation'),
|
u'name': translate('SongsPlugin.ImportWizardForm', 'Generic Document/Presentation'),
|
||||||
u'prefix': u'generic',
|
u'prefix': u'generic',
|
||||||
|
@ -332,7 +321,6 @@ class SongFormat(object):
|
||||||
return [
|
return [
|
||||||
SongFormat.OpenLyrics,
|
SongFormat.OpenLyrics,
|
||||||
SongFormat.OpenLP2,
|
SongFormat.OpenLP2,
|
||||||
SongFormat.OpenLP1,
|
|
||||||
SongFormat.Generic,
|
SongFormat.Generic,
|
||||||
SongFormat.CCLI,
|
SongFormat.CCLI,
|
||||||
SongFormat.DreamBeam,
|
SongFormat.DreamBeam,
|
||||||
|
@ -387,9 +375,7 @@ class SongFormat(object):
|
||||||
"""
|
"""
|
||||||
SongFormat.__attributes__[format][attribute] = value
|
SongFormat.__attributes__[format][attribute] = value
|
||||||
|
|
||||||
SongFormat.set(SongFormat.OpenLP1, u'availability', HAS_OPENLP1)
|
|
||||||
if HAS_OPENLP1:
|
|
||||||
SongFormat.set(SongFormat.OpenLP1, u'class', OpenLP1SongImport)
|
|
||||||
SongFormat.set(SongFormat.SongsOfFellowship, u'availability', HAS_SOF)
|
SongFormat.set(SongFormat.SongsOfFellowship, u'availability', HAS_SOF)
|
||||||
if HAS_SOF:
|
if HAS_SOF:
|
||||||
SongFormat.set(SongFormat.SongsOfFellowship, u'class', SofImport)
|
SongFormat.set(SongFormat.SongsOfFellowship, u'class', SofImport)
|
||||||
|
|
|
@ -72,27 +72,21 @@ class SongMediaItem(MediaManagerItem):
|
||||||
def __init__(self, parent, plugin):
|
def __init__(self, parent, plugin):
|
||||||
self.icon_path = u'songs/song'
|
self.icon_path = u'songs/song'
|
||||||
MediaManagerItem.__init__(self, parent, plugin)
|
MediaManagerItem.__init__(self, parent, plugin)
|
||||||
self.editSongForm = EditSongForm(self, self.main_window, self.plugin.manager)
|
|
||||||
self.openLyrics = OpenLyrics(self.plugin.manager)
|
|
||||||
self.single_service_item = False
|
self.single_service_item = False
|
||||||
self.songMaintenanceForm = SongMaintenanceForm(self.plugin.manager, self)
|
# Holds information about whether the edit is remotely triggered and which Song is required.
|
||||||
# Holds information about whether the edit is remotely triggered and
|
self.remote_song = -1
|
||||||
# which Song is required.
|
self.edit_item = None
|
||||||
self.remoteSong = -1
|
|
||||||
self.editItem = None
|
|
||||||
self.quick_preview_allowed = True
|
self.quick_preview_allowed = True
|
||||||
self.has_search = True
|
self.has_search = True
|
||||||
|
|
||||||
def _updateBackgroundAudio(self, song, item):
|
def _update_background_audio(self, song, item):
|
||||||
song.media_files = []
|
song.media_files = []
|
||||||
for i, bga in enumerate(item.background_audio):
|
for i, bga in enumerate(item.background_audio):
|
||||||
dest_file = os.path.join(
|
dest_file = os.path.join(
|
||||||
AppLocation.get_section_data_path(self.plugin.name), u'audio', str(song.id), os.path.split(bga)[1])
|
AppLocation.get_section_data_path(self.plugin.name), u'audio', str(song.id), os.path.split(bga)[1])
|
||||||
check_directory_exists(os.path.split(dest_file)[0])
|
check_directory_exists(os.path.split(dest_file)[0])
|
||||||
shutil.copyfile(os.path.join(AppLocation.get_section_data_path(u'servicemanager'), bga),
|
shutil.copyfile(os.path.join(AppLocation.get_section_data_path(u'servicemanager'), bga), dest_file)
|
||||||
dest_file)
|
song.media_files.append(MediaFile.populate(weight=i, file_name=dest_file))
|
||||||
song.media_files.append(MediaFile.populate(
|
|
||||||
weight=i, file_name=dest_file))
|
|
||||||
self.plugin.manager.save_object(song, True)
|
self.plugin.manager.save_object(song, True)
|
||||||
|
|
||||||
def add_end_header_bar(self):
|
def add_end_header_bar(self):
|
||||||
|
@ -100,12 +94,12 @@ class SongMediaItem(MediaManagerItem):
|
||||||
## Song Maintenance Button ##
|
## Song Maintenance Button ##
|
||||||
self.maintenanceAction = self.toolbar.add_toolbar_action('maintenanceAction',
|
self.maintenanceAction = self.toolbar.add_toolbar_action('maintenanceAction',
|
||||||
icon=':/songs/song_maintenance.png',
|
icon=':/songs/song_maintenance.png',
|
||||||
triggers=self.onSongMaintenanceClick)
|
triggers=self.on_song_maintenance_click)
|
||||||
self.add_search_to_toolbar()
|
self.add_search_to_toolbar()
|
||||||
# Signals and slots
|
# Signals and slots
|
||||||
Registry().register_function(u'songs_load_list', self.on_song_list_load)
|
Registry().register_function(u'songs_load_list', self.on_song_list_load)
|
||||||
Registry().register_function(u'songs_preview', self.on_preview_click)
|
Registry().register_function(u'songs_preview', self.on_preview_click)
|
||||||
QtCore.QObject.connect(self.search_text_edit, QtCore.SIGNAL(u'cleared()'), self.onClearTextButtonClick)
|
QtCore.QObject.connect(self.search_text_edit, QtCore.SIGNAL(u'cleared()'), self.on_clear_text_button_click)
|
||||||
QtCore.QObject.connect(self.search_text_edit, QtCore.SIGNAL(u'searchTypeChanged(int)'),
|
QtCore.QObject.connect(self.search_text_edit, QtCore.SIGNAL(u'searchTypeChanged(int)'),
|
||||||
self.on_search_text_button_clicked)
|
self.on_search_text_button_clicked)
|
||||||
|
|
||||||
|
@ -113,17 +107,17 @@ class SongMediaItem(MediaManagerItem):
|
||||||
create_widget_action(self.list_view, separator=True)
|
create_widget_action(self.list_view, separator=True)
|
||||||
create_widget_action(self.list_view,
|
create_widget_action(self.list_view,
|
||||||
text=translate('OpenLP.MediaManagerItem', '&Clone'), icon=u':/general/general_clone.png',
|
text=translate('OpenLP.MediaManagerItem', '&Clone'), icon=u':/general/general_clone.png',
|
||||||
triggers=self.onCloneClick)
|
triggers=self.on_clone_click)
|
||||||
|
|
||||||
def onFocus(self):
|
def on_focus(self):
|
||||||
self.search_text_edit.setFocus()
|
self.search_text_edit.setFocus()
|
||||||
|
|
||||||
def config_update(self):
|
def config_update(self):
|
||||||
"""
|
"""
|
||||||
IS triggered when the songs config is updated
|
Is triggered when the songs config is updated
|
||||||
"""
|
"""
|
||||||
log.debug(u'config_updated')
|
log.debug(u'config_updated')
|
||||||
self.searchAsYouType = Settings().value(self.settings_section + u'/search as type')
|
self.search_as_you_type = Settings().value(self.settings_section + u'/search as type')
|
||||||
self.updateServiceOnEdit = Settings().value(self.settings_section + u'/update service on edit')
|
self.updateServiceOnEdit = Settings().value(self.settings_section + u'/update service on edit')
|
||||||
self.addSongFromService = Settings().value(self.settings_section + u'/add song from service',)
|
self.addSongFromService = Settings().value(self.settings_section + u'/add song from service',)
|
||||||
|
|
||||||
|
@ -135,6 +129,12 @@ class SongMediaItem(MediaManagerItem):
|
||||||
'Maintain the lists of authors, topics and books.'))
|
'Maintain the lists of authors, topics and books.'))
|
||||||
|
|
||||||
def initialise(self):
|
def initialise(self):
|
||||||
|
"""
|
||||||
|
Initialise variables when they cannot be initialised in the constructor.
|
||||||
|
"""
|
||||||
|
self.song_maintenance_form = SongMaintenanceForm(self.plugin.manager, self)
|
||||||
|
self.edit_song_form = EditSongForm(self, self.main_window, self.plugin.manager)
|
||||||
|
self.openLyrics = OpenLyrics(self.plugin.manager)
|
||||||
self.search_text_edit.set_search_types([
|
self.search_text_edit.set_search_types([
|
||||||
(SongSearch.Entire, u':/songs/song_search_all.png',
|
(SongSearch.Entire, u':/songs/song_search_all.png',
|
||||||
translate('SongsPlugin.MediaItem', 'Entire Song'),
|
translate('SongsPlugin.MediaItem', 'Entire Song'),
|
||||||
|
@ -160,27 +160,26 @@ class SongMediaItem(MediaManagerItem):
|
||||||
Settings().setValue(u'%s/last search type' % self.settings_section, self.search_text_edit.current_search_type())
|
Settings().setValue(u'%s/last search type' % self.settings_section, self.search_text_edit.current_search_type())
|
||||||
# Reload the list considering the new search type.
|
# Reload the list considering the new search type.
|
||||||
search_keywords = unicode(self.search_text_edit.displayText())
|
search_keywords = unicode(self.search_text_edit.displayText())
|
||||||
search_results = []
|
|
||||||
search_type = self.search_text_edit.current_search_type()
|
search_type = self.search_text_edit.current_search_type()
|
||||||
if search_type == SongSearch.Entire:
|
if search_type == SongSearch.Entire:
|
||||||
log.debug(u'Entire Song Search')
|
log.debug(u'Entire Song Search')
|
||||||
search_results = self.searchEntire(search_keywords)
|
search_results = self.search_entire(search_keywords)
|
||||||
self.displayResultsSong(search_results)
|
self.display_results_song(search_results)
|
||||||
elif search_type == SongSearch.Titles:
|
elif search_type == SongSearch.Titles:
|
||||||
log.debug(u'Titles Search')
|
log.debug(u'Titles Search')
|
||||||
search_results = self.plugin.manager.get_all_objects(Song,
|
search_results = self.plugin.manager.get_all_objects(Song,
|
||||||
Song.search_title.like(u'%' + clean_string(search_keywords) + u'%'))
|
Song.search_title.like(u'%' + clean_string(search_keywords) + u'%'))
|
||||||
self.displayResultsSong(search_results)
|
self.display_results_song(search_results)
|
||||||
elif search_type == SongSearch.Lyrics:
|
elif search_type == SongSearch.Lyrics:
|
||||||
log.debug(u'Lyrics Search')
|
log.debug(u'Lyrics Search')
|
||||||
search_results = self.plugin.manager.get_all_objects(Song,
|
search_results = self.plugin.manager.get_all_objects(Song,
|
||||||
Song.search_lyrics.like(u'%' + clean_string(search_keywords) + u'%'))
|
Song.search_lyrics.like(u'%' + clean_string(search_keywords) + u'%'))
|
||||||
self.displayResultsSong(search_results)
|
self.display_results_song(search_results)
|
||||||
elif search_type == SongSearch.Authors:
|
elif search_type == SongSearch.Authors:
|
||||||
log.debug(u'Authors Search')
|
log.debug(u'Authors Search')
|
||||||
search_results = self.plugin.manager.get_all_objects(Author,
|
search_results = self.plugin.manager.get_all_objects(Author,
|
||||||
Author.display_name.like(u'%' + search_keywords + u'%'), Author.display_name.asc())
|
Author.display_name.like(u'%' + search_keywords + u'%'), Author.display_name.asc())
|
||||||
self.displayResultsAuthor(search_results)
|
self.display_results_author(search_results)
|
||||||
elif search_type == SongSearch.Books:
|
elif search_type == SongSearch.Books:
|
||||||
log.debug(u'Books Search')
|
log.debug(u'Books Search')
|
||||||
search_results = self.plugin.manager.get_all_objects(Book,
|
search_results = self.plugin.manager.get_all_objects(Book,
|
||||||
|
@ -191,15 +190,15 @@ class SongMediaItem(MediaManagerItem):
|
||||||
search_results = self.plugin.manager.get_all_objects(Book,
|
search_results = self.plugin.manager.get_all_objects(Book,
|
||||||
Book.name.like(u'%' + search_keywords[0] + u'%'), Book.name.asc())
|
Book.name.like(u'%' + search_keywords[0] + u'%'), Book.name.asc())
|
||||||
song_number = re.sub(r'[^0-9]', u'', search_keywords[2])
|
song_number = re.sub(r'[^0-9]', u'', search_keywords[2])
|
||||||
self.displayResultsBook(search_results, song_number)
|
self.display_results_book(search_results, song_number)
|
||||||
elif search_type == SongSearch.Themes:
|
elif search_type == SongSearch.Themes:
|
||||||
log.debug(u'Theme Search')
|
log.debug(u'Theme Search')
|
||||||
search_results = self.plugin.manager.get_all_objects(Song,
|
search_results = self.plugin.manager.get_all_objects(Song,
|
||||||
Song.theme_name.like(u'%' + search_keywords + u'%'))
|
Song.theme_name.like(u'%' + search_keywords + u'%'))
|
||||||
self.displayResultsSong(search_results)
|
self.display_results_song(search_results)
|
||||||
self.check_search_result()
|
self.check_search_result()
|
||||||
|
|
||||||
def searchEntire(self, search_keywords):
|
def search_entire(self, search_keywords):
|
||||||
return self.plugin.manager.get_all_objects(Song,
|
return self.plugin.manager.get_all_objects(Song,
|
||||||
or_(Song.search_title.like(u'%' + clean_string(search_keywords) + u'%'),
|
or_(Song.search_title.like(u'%' + clean_string(search_keywords) + u'%'),
|
||||||
Song.search_lyrics.like(u'%' + clean_string(search_keywords) + u'%'),
|
Song.search_lyrics.like(u'%' + clean_string(search_keywords) + u'%'),
|
||||||
|
@ -211,17 +210,16 @@ class SongMediaItem(MediaManagerItem):
|
||||||
of songs
|
of songs
|
||||||
"""
|
"""
|
||||||
log.debug(u'on_song_list_load - start')
|
log.debug(u'on_song_list_load - start')
|
||||||
# Called to redisplay the song list screen edit from a search
|
# Called to redisplay the song list screen edit from a search or from the exit of the Song edit dialog. If
|
||||||
# or from the exit of the Song edit dialog. If remote editing is active
|
# remote editing is active Trigger it and clean up so it will not update again. Push edits to the service
|
||||||
# Trigger it and clean up so it will not update again.
|
# manager to update items
|
||||||
# Push edits to the service manager to update items
|
if self.edit_item and self.updateServiceOnEdit and not self.remote_triggered:
|
||||||
if self.editItem and self.updateServiceOnEdit and not self.remote_triggered:
|
item = self.build_service_item(self.edit_item)
|
||||||
item = self.build_service_item(self.editItem)
|
|
||||||
self.service_manager.replace_service_item(item)
|
self.service_manager.replace_service_item(item)
|
||||||
self.on_search_text_button_clicked()
|
self.on_search_text_button_clicked()
|
||||||
log.debug(u'on_song_list_load - finished')
|
log.debug(u'on_song_list_load - finished')
|
||||||
|
|
||||||
def displayResultsSong(self, searchresults):
|
def display_results_song(self, searchresults):
|
||||||
log.debug(u'display results Song')
|
log.debug(u'display results Song')
|
||||||
self.save_auto_select_id()
|
self.save_auto_select_id()
|
||||||
self.list_view.clear()
|
self.list_view.clear()
|
||||||
|
@ -241,7 +239,7 @@ class SongMediaItem(MediaManagerItem):
|
||||||
self.list_view.setCurrentItem(song_name)
|
self.list_view.setCurrentItem(song_name)
|
||||||
self.auto_select_id = -1
|
self.auto_select_id = -1
|
||||||
|
|
||||||
def displayResultsAuthor(self, searchresults):
|
def display_results_author(self, searchresults):
|
||||||
log.debug(u'display results Author')
|
log.debug(u'display results Author')
|
||||||
self.list_view.clear()
|
self.list_view.clear()
|
||||||
for author in searchresults:
|
for author in searchresults:
|
||||||
|
@ -254,7 +252,7 @@ class SongMediaItem(MediaManagerItem):
|
||||||
song_name.setData(QtCore.Qt.UserRole, song.id)
|
song_name.setData(QtCore.Qt.UserRole, song.id)
|
||||||
self.list_view.addItem(song_name)
|
self.list_view.addItem(song_name)
|
||||||
|
|
||||||
def displayResultsBook(self, searchresults, song_number=False):
|
def display_results_book(self, searchresults, song_number=False):
|
||||||
log.debug(u'display results Book')
|
log.debug(u'display results Book')
|
||||||
self.list_view.clear()
|
self.list_view.clear()
|
||||||
for book in searchresults:
|
for book in searchresults:
|
||||||
|
@ -271,7 +269,7 @@ class SongMediaItem(MediaManagerItem):
|
||||||
song_name.setData(QtCore.Qt.UserRole, song.id)
|
song_name.setData(QtCore.Qt.UserRole, song.id)
|
||||||
self.list_view.addItem(song_name)
|
self.list_view.addItem(song_name)
|
||||||
|
|
||||||
def onClearTextButtonClick(self):
|
def on_clear_text_button_click(self):
|
||||||
"""
|
"""
|
||||||
Clear the search text.
|
Clear the search text.
|
||||||
"""
|
"""
|
||||||
|
@ -280,11 +278,10 @@ class SongMediaItem(MediaManagerItem):
|
||||||
|
|
||||||
def on_search_text_edit_changed(self, text):
|
def on_search_text_edit_changed(self, text):
|
||||||
"""
|
"""
|
||||||
If search as type enabled invoke the search on each key press.
|
If search as type enabled invoke the search on each key press. If the Lyrics are being searched do not start
|
||||||
If the Lyrics are being searched do not start till 7 characters
|
till 7 characters have been entered.
|
||||||
have been entered.
|
|
||||||
"""
|
"""
|
||||||
if self.searchAsYouType:
|
if self.search_as_you_type:
|
||||||
search_length = 1
|
search_length = 1
|
||||||
if self.search_text_edit.current_search_type() == SongSearch.Entire:
|
if self.search_text_edit.current_search_type() == SongSearch.Entire:
|
||||||
search_length = 4
|
search_length = 4
|
||||||
|
@ -293,7 +290,7 @@ class SongMediaItem(MediaManagerItem):
|
||||||
if len(text) > search_length:
|
if len(text) > search_length:
|
||||||
self.on_search_text_button_clicked()
|
self.on_search_text_button_clicked()
|
||||||
elif not text:
|
elif not text:
|
||||||
self.onClearTextButtonClick()
|
self.on_clear_text_button_click()
|
||||||
|
|
||||||
def on_import_click(self):
|
def on_import_click(self):
|
||||||
if not hasattr(self, u'import_wizard'):
|
if not hasattr(self, u'import_wizard'):
|
||||||
|
@ -309,33 +306,32 @@ class SongMediaItem(MediaManagerItem):
|
||||||
|
|
||||||
def on_new_click(self):
|
def on_new_click(self):
|
||||||
log.debug(u'on_new_click')
|
log.debug(u'on_new_click')
|
||||||
self.editSongForm.new_song()
|
self.edit_song_form.new_song()
|
||||||
self.editSongForm.exec_()
|
self.edit_song_form.exec_()
|
||||||
self.onClearTextButtonClick()
|
self.on_clear_text_button_click()
|
||||||
self.on_selection_change()
|
self.on_selection_change()
|
||||||
self.auto_select_id = -1
|
self.auto_select_id = -1
|
||||||
|
|
||||||
def onSongMaintenanceClick(self):
|
def on_song_maintenance_click(self):
|
||||||
self.songMaintenanceForm.exec_()
|
self.song_maintenance_form.exec_()
|
||||||
|
|
||||||
def onRemoteEdit(self, song_id, preview=False):
|
def on_remote_edit(self, song_id, preview=False):
|
||||||
"""
|
"""
|
||||||
Called by ServiceManager or SlideController by event passing
|
Called by ServiceManager or SlideController by event passing the Song Id in the payload along with an indicator
|
||||||
the Song Id in the payload along with an indicator to say which
|
to say which type of display is required.
|
||||||
type of display is required.
|
|
||||||
"""
|
"""
|
||||||
log.debug(u'onRemoteEdit for song %s' % song_id)
|
log.debug(u'on_remote_edit for song %s' % song_id)
|
||||||
song_id = int(song_id)
|
song_id = int(song_id)
|
||||||
valid = self.plugin.manager.get_object(Song, song_id)
|
valid = self.plugin.manager.get_object(Song, song_id)
|
||||||
if valid:
|
if valid:
|
||||||
self.editSongForm.load_song(song_id, preview)
|
self.edit_song_form.load_song(song_id, preview)
|
||||||
if self.editSongForm.exec_() == QtGui.QDialog.Accepted:
|
if self.edit_song_form.exec_() == QtGui.QDialog.Accepted:
|
||||||
self.auto_select_id = -1
|
self.auto_select_id = -1
|
||||||
self.on_song_list_load()
|
self.on_song_list_load()
|
||||||
self.remoteSong = song_id
|
self.remote_song = song_id
|
||||||
self.remote_triggered = True
|
self.remote_triggered = True
|
||||||
item = self.build_service_item(remote=True)
|
item = self.build_service_item(remote=True)
|
||||||
self.remoteSong = -1
|
self.remote_song = -1
|
||||||
self.remote_triggered = None
|
self.remote_triggered = None
|
||||||
if item:
|
if item:
|
||||||
return item
|
return item
|
||||||
|
@ -347,13 +343,13 @@ class SongMediaItem(MediaManagerItem):
|
||||||
"""
|
"""
|
||||||
log.debug(u'on_edit_click')
|
log.debug(u'on_edit_click')
|
||||||
if check_item_selected(self.list_view, UiStrings().SelectEdit):
|
if check_item_selected(self.list_view, UiStrings().SelectEdit):
|
||||||
self.editItem = self.list_view.currentItem()
|
self.edit_item = self.list_view.currentItem()
|
||||||
item_id = self.editItem.data(QtCore.Qt.UserRole)
|
item_id = self.edit_item.data(QtCore.Qt.UserRole)
|
||||||
self.editSongForm.load_song(item_id, False)
|
self.edit_song_form.load_song(item_id, False)
|
||||||
self.editSongForm.exec_()
|
self.edit_song_form.exec_()
|
||||||
self.auto_select_id = -1
|
self.auto_select_id = -1
|
||||||
self.on_song_list_load()
|
self.on_song_list_load()
|
||||||
self.editItem = None
|
self.edit_item = None
|
||||||
|
|
||||||
def on_delete_click(self):
|
def on_delete_click(self):
|
||||||
"""
|
"""
|
||||||
|
@ -362,11 +358,11 @@ class SongMediaItem(MediaManagerItem):
|
||||||
if check_item_selected(self.list_view, UiStrings().SelectDelete):
|
if check_item_selected(self.list_view, UiStrings().SelectDelete):
|
||||||
items = self.list_view.selectedIndexes()
|
items = self.list_view.selectedIndexes()
|
||||||
if QtGui.QMessageBox.question(self,
|
if QtGui.QMessageBox.question(self,
|
||||||
UiStrings().ConfirmDelete,
|
UiStrings().ConfirmDelete,
|
||||||
translate('SongsPlugin.MediaItem', 'Are you sure you want to delete the %n selected song(s)?', '',
|
translate('SongsPlugin.MediaItem', 'Are you sure you want to delete the %n selected song(s)?', '',
|
||||||
QtCore.QCoreApplication.CodecForTr, len(items)),
|
QtCore.QCoreApplication.CodecForTr, len(items)),
|
||||||
QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Yes | QtGui.QMessageBox.No),
|
QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Yes | QtGui.QMessageBox.No),
|
||||||
QtGui.QMessageBox.Yes) == QtGui.QMessageBox.No:
|
QtGui.QMessageBox.Yes) == QtGui.QMessageBox.No:
|
||||||
return
|
return
|
||||||
self.application.set_busy_cursor()
|
self.application.set_busy_cursor()
|
||||||
self.main_window.display_progress_bar(len(items))
|
self.main_window.display_progress_bar(len(items))
|
||||||
|
@ -390,14 +386,14 @@ class SongMediaItem(MediaManagerItem):
|
||||||
self.application.set_normal_cursor()
|
self.application.set_normal_cursor()
|
||||||
self.on_search_text_button_clicked()
|
self.on_search_text_button_clicked()
|
||||||
|
|
||||||
def onCloneClick(self):
|
def on_clone_click(self):
|
||||||
"""
|
"""
|
||||||
Clone a Song
|
Clone a Song
|
||||||
"""
|
"""
|
||||||
log.debug(u'onCloneClick')
|
log.debug(u'on_clone_click')
|
||||||
if check_item_selected(self.list_view, UiStrings().SelectEdit):
|
if check_item_selected(self.list_view, UiStrings().SelectEdit):
|
||||||
self.editItem = self.list_view.currentItem()
|
self.edit_item = self.list_view.currentItem()
|
||||||
item_id = self.editItem.data(QtCore.Qt.UserRole)
|
item_id = self.edit_item.data(QtCore.Qt.UserRole)
|
||||||
old_song = self.plugin.manager.get_object(Song, item_id)
|
old_song = self.plugin.manager.get_object(Song, item_id)
|
||||||
song_xml = self.openLyrics.song_to_xml(old_song)
|
song_xml = self.openLyrics.song_to_xml(old_song)
|
||||||
new_song = self.openLyrics.xml_to_song(song_xml)
|
new_song = self.openLyrics.xml_to_song(song_xml)
|
||||||
|
@ -411,8 +407,8 @@ class SongMediaItem(MediaManagerItem):
|
||||||
"""
|
"""
|
||||||
Generate the slide data. Needs to be implemented by the plugin.
|
Generate the slide data. Needs to be implemented by the plugin.
|
||||||
"""
|
"""
|
||||||
log.debug(u'generate_slide_data: %s, %s, %s' % (service_item, item, self.remoteSong))
|
log.debug(u'generate_slide_data: %s, %s, %s' % (service_item, item, self.remote_song))
|
||||||
item_id = self._get_id_of_item_to_generate(item, self.remoteSong)
|
item_id = self._get_id_of_item_to_generate(item, self.remote_song)
|
||||||
service_item.add_capability(ItemCapabilities.CanEdit)
|
service_item.add_capability(ItemCapabilities.CanEdit)
|
||||||
service_item.add_capability(ItemCapabilities.CanPreview)
|
service_item.add_capability(ItemCapabilities.CanPreview)
|
||||||
service_item.add_capability(ItemCapabilities.CanLoop)
|
service_item.add_capability(ItemCapabilities.CanLoop)
|
||||||
|
@ -430,8 +426,8 @@ class SongMediaItem(MediaManagerItem):
|
||||||
verse_tags_translated = True
|
verse_tags_translated = True
|
||||||
if not song.verse_order.strip():
|
if not song.verse_order.strip():
|
||||||
for verse in verse_list:
|
for verse in verse_list:
|
||||||
# We cannot use from_loose_input() here, because database
|
# We cannot use from_loose_input() here, because database is supposed to contain English lowercase
|
||||||
# is supposed to contain English lowercase singlechar tags.
|
# singlechar tags.
|
||||||
verse_tag = verse[0][u'type']
|
verse_tag = verse[0][u'type']
|
||||||
verse_index = None
|
verse_index = None
|
||||||
if len(verse_tag) > 1:
|
if len(verse_tag) > 1:
|
||||||
|
@ -463,16 +459,7 @@ class SongMediaItem(MediaManagerItem):
|
||||||
for slide in verses:
|
for slide in verses:
|
||||||
service_item.add_from_text(unicode(slide))
|
service_item.add_from_text(unicode(slide))
|
||||||
service_item.title = song.title
|
service_item.title = song.title
|
||||||
author_list = [unicode(author.display_name) for author in song.authors]
|
author_list = self.generate_footer(service_item, song)
|
||||||
service_item.raw_footer.append(song.title)
|
|
||||||
service_item.raw_footer.append(create_separated_list(author_list))
|
|
||||||
service_item.raw_footer.append(song.copyright)
|
|
||||||
if Settings().value(u'general/ccli number'):
|
|
||||||
service_item.raw_footer.append(translate('SongsPlugin.MediaItem', 'CCLI License: ') +
|
|
||||||
Settings().value(u'general/ccli number'))
|
|
||||||
service_item.audit = [
|
|
||||||
song.title, author_list, song.copyright, unicode(song.ccli_number)
|
|
||||||
]
|
|
||||||
service_item.data_string = {u'title': song.search_title, u'authors': u', '.join(author_list)}
|
service_item.data_string = {u'title': song.search_title, u'authors': u', '.join(author_list)}
|
||||||
service_item.xml_version = self.openLyrics.song_to_xml(song)
|
service_item.xml_version = self.openLyrics.song_to_xml(song)
|
||||||
# Add the audio file to the service item.
|
# Add the audio file to the service item.
|
||||||
|
@ -481,6 +468,30 @@ class SongMediaItem(MediaManagerItem):
|
||||||
service_item.background_audio = [m.file_name for m in song.media_files]
|
service_item.background_audio = [m.file_name for m in song.media_files]
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def generate_footer(self, item, song):
|
||||||
|
"""
|
||||||
|
Generates the song footer based on a song and adds details to a service item.
|
||||||
|
author_list is only required for initial song generation.
|
||||||
|
|
||||||
|
``item``
|
||||||
|
The service item to be amended
|
||||||
|
|
||||||
|
``song``
|
||||||
|
The song to be used to generate the footer
|
||||||
|
"""
|
||||||
|
author_list = [unicode(author.display_name) for author in song.authors]
|
||||||
|
item.audit = [
|
||||||
|
song.title, author_list, song.copyright, unicode(song.ccli_number)
|
||||||
|
]
|
||||||
|
item.raw_footer = []
|
||||||
|
item.raw_footer.append(song.title)
|
||||||
|
item.raw_footer.append(create_separated_list(author_list))
|
||||||
|
item.raw_footer.append(song.copyright)
|
||||||
|
if Settings().value(u'core/ccli number'):
|
||||||
|
item.raw_footer.append(translate('SongsPlugin.MediaItem', 'CCLI License: ') +
|
||||||
|
Settings().value(u'core/ccli number'))
|
||||||
|
return author_list
|
||||||
|
|
||||||
def service_load(self, item):
|
def service_load(self, item):
|
||||||
"""
|
"""
|
||||||
Triggered by a song being loaded by the service manager.
|
Triggered by a song being loaded by the service manager.
|
||||||
|
@ -489,9 +500,8 @@ class SongMediaItem(MediaManagerItem):
|
||||||
if self.plugin.status != PluginStatus.Active or not item.data_string:
|
if self.plugin.status != PluginStatus.Active or not item.data_string:
|
||||||
return
|
return
|
||||||
if item.data_string[u'title'].find(u'@') == -1:
|
if item.data_string[u'title'].find(u'@') == -1:
|
||||||
# This file seems to be an old one (prior to 1.9.5), which means,
|
# FIXME: This file seems to be an old one (prior to 1.9.5), which means, that the search title
|
||||||
# that the search title (data_string[u'title']) is probably wrong.
|
# (data_string[u'title']) is probably wrong. We add "@" to search title and hope that we do not add any
|
||||||
# We add "@" to search title and hope that we do not add any
|
|
||||||
# duplicate. This should work for songs without alternate title.
|
# duplicate. This should work for songs without alternate title.
|
||||||
search_results = self.plugin.manager.get_all_objects(Song,
|
search_results = self.plugin.manager.get_all_objects(Song,
|
||||||
Song.search_title == (re.compile(r'\W+', re.UNICODE).sub(u' ',
|
Song.search_title == (re.compile(r'\W+', re.UNICODE).sub(u' ',
|
||||||
|
@ -499,9 +509,8 @@ class SongMediaItem(MediaManagerItem):
|
||||||
else:
|
else:
|
||||||
search_results = self.plugin.manager.get_all_objects(Song,
|
search_results = self.plugin.manager.get_all_objects(Song,
|
||||||
Song.search_title == item.data_string[u'title'], Song.search_title.asc())
|
Song.search_title == item.data_string[u'title'], Song.search_title.asc())
|
||||||
editId = 0
|
edit_id = 0
|
||||||
add_song = True
|
add_song = True
|
||||||
temporary = False
|
|
||||||
if search_results:
|
if search_results:
|
||||||
for song in search_results:
|
for song in search_results:
|
||||||
author_list = item.data_string[u'authors']
|
author_list = item.data_string[u'authors']
|
||||||
|
@ -514,16 +523,16 @@ class SongMediaItem(MediaManagerItem):
|
||||||
break
|
break
|
||||||
if same_authors and author_list.strip(u', ') == u'':
|
if same_authors and author_list.strip(u', ') == u'':
|
||||||
add_song = False
|
add_song = False
|
||||||
editId = song.id
|
edit_id = song.id
|
||||||
break
|
break
|
||||||
# If there's any backing tracks, copy them over.
|
# If there's any backing tracks, copy them over.
|
||||||
if item.background_audio:
|
if item.background_audio:
|
||||||
self._updateBackgroundAudio(song, item)
|
self._update_background_audio(song, item)
|
||||||
if add_song and self.addSongFromService:
|
if add_song and self.addSongFromService:
|
||||||
song = self.openLyrics.xml_to_song(item.xml_version)
|
song = self.openLyrics.xml_to_song(item.xml_version)
|
||||||
# If there's any backing tracks, copy them over.
|
# If there's any backing tracks, copy them over.
|
||||||
if item.background_audio:
|
if item.background_audio:
|
||||||
self._updateBackgroundAudio(song, item)
|
self._update_background_audio(song, item)
|
||||||
editId = song.id
|
editId = song.id
|
||||||
self.on_search_text_button_clicked()
|
self.on_search_text_button_clicked()
|
||||||
elif add_song and not self.addSongFromService:
|
elif add_song and not self.addSongFromService:
|
||||||
|
@ -531,16 +540,16 @@ class SongMediaItem(MediaManagerItem):
|
||||||
song = self.openLyrics.xml_to_song(item.xml_version, True)
|
song = self.openLyrics.xml_to_song(item.xml_version, True)
|
||||||
# If there's any backing tracks, copy them over.
|
# If there's any backing tracks, copy them over.
|
||||||
if item.background_audio:
|
if item.background_audio:
|
||||||
self._updateBackgroundAudio(song, item)
|
self._update_background_audio(song, item)
|
||||||
editId = song.id
|
edit_id = song.id
|
||||||
temporary = True
|
# Update service with correct song id and return it to caller.
|
||||||
# Update service with correct song id.
|
item.edit_id = edit_id
|
||||||
if editId:
|
self.generate_footer(item, song)
|
||||||
self.service_manager.service_item_update(editId, item.unique_identifier, temporary)
|
return item
|
||||||
|
|
||||||
def search(self, string, showError):
|
def search(self, string, showError):
|
||||||
"""
|
"""
|
||||||
Search for some songs
|
Search for some songs
|
||||||
"""
|
"""
|
||||||
search_results = self.searchEntire(string)
|
search_results = self.search_entire(string)
|
||||||
return [[song.id, song.title] for song in search_results]
|
return [[song.id, song.title] for song in search_results]
|
||||||
|
|
|
@ -1,227 +0,0 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
# OpenLP - Open Source Lyrics Projection #
|
|
||||||
# --------------------------------------------------------------------------- #
|
|
||||||
# Copyright (c) 2008-2013 Raoul Snyman #
|
|
||||||
# Portions copyright (c) 2008-2013 Tim Bentley, Gerald Britton, Jonathan #
|
|
||||||
# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, #
|
|
||||||
# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. #
|
|
||||||
# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, #
|
|
||||||
# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, #
|
|
||||||
# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, #
|
|
||||||
# Frode Woldsund, Martin Zibricky, Patrick Zimmermann #
|
|
||||||
# --------------------------------------------------------------------------- #
|
|
||||||
# This program is free software; you can redistribute it and/or modify it #
|
|
||||||
# under the terms of the GNU General Public License as published by the Free #
|
|
||||||
# Software Foundation; version 2 of the License. #
|
|
||||||
# #
|
|
||||||
# This program is distributed in the hope that it will be useful, but WITHOUT #
|
|
||||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
|
|
||||||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
|
|
||||||
# more details. #
|
|
||||||
# #
|
|
||||||
# You should have received a copy of the GNU General Public License along #
|
|
||||||
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
|
|
||||||
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
|
||||||
###############################################################################
|
|
||||||
"""
|
|
||||||
The :mod:`olp1import` module provides the functionality for importing
|
|
||||||
openlp.org 1.x song databases into the current installation database.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import logging
|
|
||||||
from chardet.universaldetector import UniversalDetector
|
|
||||||
import sqlite
|
|
||||||
import sys
|
|
||||||
import os
|
|
||||||
|
|
||||||
from openlp.core.lib import Registry, translate
|
|
||||||
from openlp.plugins.songs.lib import retrieve_windows_encoding
|
|
||||||
from songimport import SongImport
|
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
class OpenLP1SongImport(SongImport):
|
|
||||||
"""
|
|
||||||
The :class:`OpenLP1SongImport` class provides OpenLP with the ability to
|
|
||||||
import song databases from installations of openlp.org 1.x.
|
|
||||||
"""
|
|
||||||
lastEncoding = u'windows-1252'
|
|
||||||
|
|
||||||
def __init__(self, manager, **kwargs):
|
|
||||||
"""
|
|
||||||
Initialise the import.
|
|
||||||
|
|
||||||
``manager``
|
|
||||||
The song manager for the running OpenLP installation.
|
|
||||||
|
|
||||||
``filename``
|
|
||||||
The database providing the data to import.
|
|
||||||
"""
|
|
||||||
SongImport.__init__(self, manager, **kwargs)
|
|
||||||
|
|
||||||
def doImport(self):
|
|
||||||
"""
|
|
||||||
Run the import for an openlp.org 1.x song database.
|
|
||||||
"""
|
|
||||||
if not self.import_source.endswith(u'.olp'):
|
|
||||||
self.logError(self.import_source,
|
|
||||||
translate('SongsPlugin.OpenLP1SongImport', 'Not a valid openlp.org 1.x song database.'))
|
|
||||||
return
|
|
||||||
encoding = self.getEncoding()
|
|
||||||
if not encoding:
|
|
||||||
return
|
|
||||||
# Connect to the database.
|
|
||||||
connection = sqlite.connect(self.import_source, mode=0444, encoding=(encoding, 'replace'))
|
|
||||||
cursor = connection.cursor()
|
|
||||||
# Determine if the db supports linking audio to songs.
|
|
||||||
cursor.execute(u'SELECT name FROM sqlite_master '
|
|
||||||
u'WHERE type = \'table\' AND name = \'tracks\'')
|
|
||||||
db_has_tracks = len(cursor.fetchall()) > 0
|
|
||||||
# Determine if the db contains theme information.
|
|
||||||
cursor.execute(u'SELECT name FROM sqlite_master '
|
|
||||||
u'WHERE type = \'table\' AND name = \'settings\'')
|
|
||||||
db_has_themes = len(cursor.fetchall()) > 0
|
|
||||||
# "cache" our list of authors.
|
|
||||||
cursor.execute(u'-- types int, unicode')
|
|
||||||
cursor.execute(u'SELECT authorid, authorname FROM authors')
|
|
||||||
authors = cursor.fetchall()
|
|
||||||
if db_has_tracks:
|
|
||||||
# "cache" our list of tracks.
|
|
||||||
cursor.execute(u'-- types int, unicode')
|
|
||||||
cursor.execute(u'SELECT trackid, fulltrackname FROM tracks')
|
|
||||||
tracks = cursor.fetchall()
|
|
||||||
if db_has_themes:
|
|
||||||
# "cache" our list of themes.
|
|
||||||
themes = {}
|
|
||||||
cursor.execute(u'-- types int, unicode')
|
|
||||||
cursor.execute(u'SELECT settingsid, settingsname FROM settings')
|
|
||||||
for theme_id, theme_name in cursor.fetchall():
|
|
||||||
if theme_name in self.theme_manager.get_themes():
|
|
||||||
themes[theme_id] = theme_name
|
|
||||||
# Import the songs.
|
|
||||||
cursor.execute(u'-- types int, unicode, unicode, unicode')
|
|
||||||
cursor.execute(u'SELECT songid, songtitle, lyrics || \'\' AS ' \
|
|
||||||
u'lyrics, copyrightinfo FROM songs')
|
|
||||||
songs = cursor.fetchall()
|
|
||||||
self.import_wizard.progress_bar.setMaximum(len(songs))
|
|
||||||
for song in songs:
|
|
||||||
self.setDefaults()
|
|
||||||
if self.stop_import_flag:
|
|
||||||
break
|
|
||||||
song_id = song[0]
|
|
||||||
self.title = song[1]
|
|
||||||
lyrics = song[2].replace(u'\r\n', u'\n')
|
|
||||||
self.addCopyright(song[3])
|
|
||||||
if db_has_themes:
|
|
||||||
cursor.execute(u'-- types int')
|
|
||||||
cursor.execute(
|
|
||||||
u'SELECT settingsid FROM songs WHERE songid = %s' % song_id)
|
|
||||||
theme_id = cursor.fetchone()[0]
|
|
||||||
self.themeName = themes.get(theme_id, u'')
|
|
||||||
verses = lyrics.split(u'\n\n')
|
|
||||||
for verse in verses:
|
|
||||||
if verse.strip():
|
|
||||||
self.addVerse(verse.strip())
|
|
||||||
cursor.execute(u'-- types int')
|
|
||||||
cursor.execute(u'SELECT authorid FROM songauthors '
|
|
||||||
u'WHERE songid = %s' % song_id)
|
|
||||||
author_ids = cursor.fetchall()
|
|
||||||
for author_id in author_ids:
|
|
||||||
if self.stop_import_flag:
|
|
||||||
break
|
|
||||||
for author in authors:
|
|
||||||
if author[0] == author_id[0]:
|
|
||||||
self.parse_author(author[1])
|
|
||||||
break
|
|
||||||
if self.stop_import_flag:
|
|
||||||
break
|
|
||||||
if db_has_tracks:
|
|
||||||
cursor.execute(u'-- types int, int')
|
|
||||||
cursor.execute(u'SELECT trackid, listindex '
|
|
||||||
u'FROM songtracks '
|
|
||||||
u'WHERE songid = %s ORDER BY listindex' % song_id)
|
|
||||||
track_ids = cursor.fetchall()
|
|
||||||
for track_id, listindex in track_ids:
|
|
||||||
if self.stop_import_flag:
|
|
||||||
break
|
|
||||||
for track in tracks:
|
|
||||||
if track[0] == track_id:
|
|
||||||
media_file = self.expandMediaFile(track[1])
|
|
||||||
self.addMediaFile(media_file, listindex)
|
|
||||||
break
|
|
||||||
if self.stop_import_flag:
|
|
||||||
break
|
|
||||||
if not self.finish():
|
|
||||||
self.logError(self.import_source)
|
|
||||||
|
|
||||||
def getEncoding(self):
|
|
||||||
"""
|
|
||||||
Detect character encoding of an openlp.org 1.x song database.
|
|
||||||
"""
|
|
||||||
# Connect to the database.
|
|
||||||
connection = sqlite.connect(self.import_source.encode(
|
|
||||||
sys.getfilesystemencoding()), mode=0444)
|
|
||||||
cursor = connection.cursor()
|
|
||||||
|
|
||||||
detector = UniversalDetector()
|
|
||||||
# Detect charset by authors.
|
|
||||||
cursor.execute(u'SELECT authorname FROM authors')
|
|
||||||
authors = cursor.fetchall()
|
|
||||||
for author in authors:
|
|
||||||
detector.feed(author[0])
|
|
||||||
if detector.done:
|
|
||||||
detector.close()
|
|
||||||
return detector.result[u'encoding']
|
|
||||||
# Detect charset by songs.
|
|
||||||
cursor.execute(u'SELECT songtitle, copyrightinfo, '
|
|
||||||
u'lyrics || \'\' AS lyrics FROM songs')
|
|
||||||
songs = cursor.fetchall()
|
|
||||||
for index in [0, 1, 2]:
|
|
||||||
for song in songs:
|
|
||||||
detector.feed(song[index])
|
|
||||||
if detector.done:
|
|
||||||
detector.close()
|
|
||||||
return detector.result[u'encoding']
|
|
||||||
# Detect charset by songs.
|
|
||||||
cursor.execute(u'SELECT name FROM sqlite_master '
|
|
||||||
u'WHERE type = \'table\' AND name = \'tracks\'')
|
|
||||||
if cursor.fetchall():
|
|
||||||
cursor.execute(u'SELECT fulltrackname FROM tracks')
|
|
||||||
tracks = cursor.fetchall()
|
|
||||||
for track in tracks:
|
|
||||||
detector.feed(track[0])
|
|
||||||
if detector.done:
|
|
||||||
detector.close()
|
|
||||||
return detector.result[u'encoding']
|
|
||||||
detector.close()
|
|
||||||
return retrieve_windows_encoding(detector.result[u'encoding'])
|
|
||||||
|
|
||||||
def expandMediaFile(self, filename):
|
|
||||||
"""
|
|
||||||
When you're on Windows, this function expands the file name to include
|
|
||||||
the path to OpenLP's application data directory. If you are not on
|
|
||||||
Windows, it returns the original file name.
|
|
||||||
|
|
||||||
``filename``
|
|
||||||
The filename to expand.
|
|
||||||
"""
|
|
||||||
if sys.platform != u'win32' and not os.environ.get(u'ALLUSERSPROFILE') and not os.environ.get(u'APPDATA'):
|
|
||||||
return filename
|
|
||||||
common_app_data = os.path.join(os.environ[u'ALLUSERSPROFILE'],
|
|
||||||
os.path.split(os.environ[u'APPDATA'])[1])
|
|
||||||
if not common_app_data:
|
|
||||||
return filename
|
|
||||||
return os.path.join(common_app_data, u'openlp.org', 'Audio', filename)
|
|
||||||
|
|
||||||
def _get_theme_manager(self):
|
|
||||||
"""
|
|
||||||
Adds the theme manager to the class dynamically
|
|
||||||
"""
|
|
||||||
if not hasattr(self, u'_theme_manager'):
|
|
||||||
self._theme_manager = Registry().get(u'theme_manager')
|
|
||||||
return self._theme_manager
|
|
||||||
|
|
||||||
theme_manager = property(_get_theme_manager)
|
|
|
@ -235,8 +235,7 @@ class SongsPlugin(Plugin):
|
||||||
u'delete': translate('SongsPlugin', 'Delete the selected song.'),
|
u'delete': translate('SongsPlugin', 'Delete the selected song.'),
|
||||||
u'preview': translate('SongsPlugin', 'Preview the selected song.'),
|
u'preview': translate('SongsPlugin', 'Preview the selected song.'),
|
||||||
u'live': translate('SongsPlugin', 'Send the selected song live.'),
|
u'live': translate('SongsPlugin', 'Send the selected song live.'),
|
||||||
u'service': translate('SongsPlugin',
|
u'service': translate('SongsPlugin', 'Add the selected song to the service.')
|
||||||
'Add the selected song to the service.')
|
|
||||||
}
|
}
|
||||||
self.set_plugin_ui_text_strings(tooltips)
|
self.set_plugin_ui_text_strings(tooltips)
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,6 @@
|
||||||
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
||||||
###############################################################################
|
###############################################################################
|
||||||
"""
|
"""
|
||||||
The :mod:`songusage` module contains the Song Usage plugin. The Song Usage
|
The :mod:`songusage` module contains the Song Usage plugin. The Song Usage plugin provides auditing capabilities for
|
||||||
plugin provides auditing capabilities for reporting the songs you are using to
|
reporting the songs you are using to copyright license organisations.
|
||||||
copyright license organisations.
|
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -55,7 +55,8 @@ class Ui_SongUsageDeleteDialog(object):
|
||||||
self.retranslateUi(song_usage_delete_dialog)
|
self.retranslateUi(song_usage_delete_dialog)
|
||||||
|
|
||||||
def retranslateUi(self, song_usage_delete_dialog):
|
def retranslateUi(self, song_usage_delete_dialog):
|
||||||
song_usage_delete_dialog.setWindowTitle(translate('SongUsagePlugin.SongUsageDeleteForm', 'Delete Song Usage Data'))
|
song_usage_delete_dialog.setWindowTitle(
|
||||||
|
translate('SongUsagePlugin.SongUsageDeleteForm', 'Delete Song Usage Data'))
|
||||||
self.delete_label.setText(
|
self.delete_label.setText(
|
||||||
translate('SongUsagePlugin.SongUsageDeleteForm', 'Select the date up to which the song usage data '
|
translate('SongUsagePlugin.SongUsageDeleteForm', 'Select the date up to which the song usage data '
|
||||||
'should be deleted. All data recorded before this date will be permanently deleted.'))
|
'should be deleted. All data recorded before this date will be permanently deleted.'))
|
||||||
|
|
|
@ -81,7 +81,8 @@ class Ui_SongUsageDetailDialog(object):
|
||||||
self.save_file_push_button.clicked.connect(song_usage_detail_dialog.define_output_location)
|
self.save_file_push_button.clicked.connect(song_usage_detail_dialog.define_output_location)
|
||||||
|
|
||||||
def retranslateUi(self, song_usage_detail_dialog):
|
def retranslateUi(self, song_usage_detail_dialog):
|
||||||
song_usage_detail_dialog.setWindowTitle(translate('SongUsagePlugin.SongUsageDetailForm', 'Song Usage Extraction'))
|
song_usage_detail_dialog.setWindowTitle(
|
||||||
|
translate('SongUsagePlugin.SongUsageDetailForm', 'Song Usage Extraction'))
|
||||||
self.date_range_group_box.setTitle(translate('SongUsagePlugin.SongUsageDetailForm', 'Select Date Range'))
|
self.date_range_group_box.setTitle(translate('SongUsagePlugin.SongUsageDetailForm', 'Select Date Range'))
|
||||||
self.to_label.setText(translate('SongUsagePlugin.SongUsageDetailForm', 'to'))
|
self.to_label.setText(translate('SongUsagePlugin.SongUsageDetailForm', 'to'))
|
||||||
self.file_group_box.setTitle(translate('SongUsagePlugin.SongUsageDetailForm', 'Report Location'))
|
self.file_group_box.setTitle(translate('SongUsagePlugin.SongUsageDetailForm', 'Report Location'))
|
||||||
|
|
|
@ -36,12 +36,14 @@ from sqlalchemy.orm import mapper
|
||||||
|
|
||||||
from openlp.core.lib.db import BaseModel, init_db
|
from openlp.core.lib.db import BaseModel, init_db
|
||||||
|
|
||||||
|
|
||||||
class SongUsageItem(BaseModel):
|
class SongUsageItem(BaseModel):
|
||||||
"""
|
"""
|
||||||
SongUsageItem model
|
SongUsageItem model
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def init_schema(url):
|
def init_schema(url):
|
||||||
"""
|
"""
|
||||||
Setup the songusage database connection and initialise the database schema
|
Setup the songusage database connection and initialise the database schema
|
||||||
|
|
|
@ -48,11 +48,11 @@ if QtCore.QDate().currentDate().month() < 9:
|
||||||
|
|
||||||
|
|
||||||
__default_settings__ = {
|
__default_settings__ = {
|
||||||
u'songusage/db type': u'sqlite',
|
u'songusage/db type': u'sqlite',
|
||||||
u'songusage/active': False,
|
u'songusage/active': False,
|
||||||
u'songusage/to date': QtCore.QDate(YEAR, 8, 31),
|
u'songusage/to date': QtCore.QDate(YEAR, 8, 31),
|
||||||
u'songusage/from date': QtCore.QDate(YEAR - 1, 9, 1),
|
u'songusage/from date': QtCore.QDate(YEAR - 1, 9, 1),
|
||||||
u'songusage/last directory export': u''
|
u'songusage/last directory export': u''
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -76,12 +76,10 @@ class SongUsagePlugin(Plugin):
|
||||||
|
|
||||||
def add_tools_menu_item(self, tools_menu):
|
def add_tools_menu_item(self, tools_menu):
|
||||||
"""
|
"""
|
||||||
Give the SongUsage plugin the opportunity to add items to the
|
Give the SongUsage plugin the opportunity to add items to the **Tools** menu.
|
||||||
**Tools** menu.
|
|
||||||
|
|
||||||
``tools_menu``
|
``tools_menu``
|
||||||
The actual **Tools** menu item, so that your actions can
|
The actual **Tools** menu item, so that your actions can use it as their parent.
|
||||||
use it as their parent.
|
|
||||||
"""
|
"""
|
||||||
log.info(u'add tools menu')
|
log.info(u'add tools menu')
|
||||||
self.toolsMenu = tools_menu
|
self.toolsMenu = tools_menu
|
||||||
|
@ -218,8 +216,8 @@ class SongUsagePlugin(Plugin):
|
||||||
self.song_usage_detail_form.exec_()
|
self.song_usage_detail_form.exec_()
|
||||||
|
|
||||||
def about(self):
|
def about(self):
|
||||||
about_text = translate('SongUsagePlugin', '<strong>SongUsage Plugin'
|
about_text = translate('SongUsagePlugin',
|
||||||
'</strong><br />This plugin tracks the usage of songs in services.')
|
'<strong>SongUsage Plugin</strong><br />This plugin tracks the usage of songs in services.')
|
||||||
return about_text
|
return about_text
|
||||||
|
|
||||||
def set_plugin_text_strings(self):
|
def set_plugin_text_strings(self):
|
||||||
|
|
|
@ -79,8 +79,9 @@ MODULES = [
|
||||||
'lxml',
|
'lxml',
|
||||||
'chardet',
|
'chardet',
|
||||||
'enchant',
|
'enchant',
|
||||||
'BeautifulSoup',
|
'bs4',
|
||||||
'mako',
|
'mako',
|
||||||
|
'cherrypy',
|
||||||
'migrate',
|
'migrate',
|
||||||
'uno',
|
'uno',
|
||||||
'icu',
|
'icu',
|
||||||
|
@ -88,7 +89,6 @@ MODULES = [
|
||||||
|
|
||||||
|
|
||||||
OPTIONAL_MODULES = [
|
OPTIONAL_MODULES = [
|
||||||
('sqlite', ' (SQLite 2 support)'),
|
|
||||||
('MySQLdb', ' (MySQL support)'),
|
('MySQLdb', ' (MySQL support)'),
|
||||||
('psycopg2', ' (PostgreSQL support)'),
|
('psycopg2', ' (PostgreSQL support)'),
|
||||||
('nose', ' (testing framework)'),
|
('nose', ' (testing framework)'),
|
||||||
|
|
|
@ -1,13 +1,20 @@
|
||||||
"""
|
"""
|
||||||
Package to test the openlp.core.lib package.
|
Package to test the openlp.core.lib package.
|
||||||
"""
|
"""
|
||||||
|
import os
|
||||||
|
|
||||||
from unittest import TestCase
|
from unittest import TestCase
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
from mock import MagicMock, patch
|
from mock import MagicMock, patch
|
||||||
|
from PyQt4 import QtCore, QtGui
|
||||||
|
|
||||||
|
from openlp.core.lib import str_to_bool, create_thumb, translate, check_directory_exists, get_text_file_string, \
|
||||||
|
build_icon, image_to_byte, check_item_selected, validate_thumb, create_separated_list, clean_tags, expand_tags
|
||||||
|
|
||||||
|
|
||||||
|
TEST_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), u'..', u'..', u'resources'))
|
||||||
|
|
||||||
from openlp.core.lib import str_to_bool, translate, check_directory_exists, get_text_file_string, build_icon, \
|
|
||||||
image_to_byte, check_item_selected, validate_thumb, create_separated_list, clean_tags, expand_tags
|
|
||||||
|
|
||||||
class TestLib(TestCase):
|
class TestLib(TestCase):
|
||||||
|
|
||||||
|
@ -15,7 +22,7 @@ class TestLib(TestCase):
|
||||||
"""
|
"""
|
||||||
Test the str_to_bool function with boolean input
|
Test the str_to_bool function with boolean input
|
||||||
"""
|
"""
|
||||||
#GIVEN: A boolean value set to true
|
# GIVEN: A boolean value set to true
|
||||||
true_boolean = True
|
true_boolean = True
|
||||||
|
|
||||||
# WHEN: We "convert" it to a bool
|
# WHEN: We "convert" it to a bool
|
||||||
|
@ -25,7 +32,7 @@ class TestLib(TestCase):
|
||||||
assert isinstance(true_result, bool), u'The result should be a boolean'
|
assert isinstance(true_result, bool), u'The result should be a boolean'
|
||||||
assert true_result is True, u'The result should be True'
|
assert true_result is True, u'The result should be True'
|
||||||
|
|
||||||
#GIVEN: A boolean value set to false
|
# GIVEN: A boolean value set to false
|
||||||
false_boolean = False
|
false_boolean = False
|
||||||
|
|
||||||
# WHEN: We "convert" it to a bool
|
# WHEN: We "convert" it to a bool
|
||||||
|
@ -125,7 +132,7 @@ class TestLib(TestCase):
|
||||||
Test the check_directory_exists() function
|
Test the check_directory_exists() function
|
||||||
"""
|
"""
|
||||||
with patch(u'openlp.core.lib.os.path.exists') as mocked_exists, \
|
with patch(u'openlp.core.lib.os.path.exists') as mocked_exists, \
|
||||||
patch(u'openlp.core.lib.os.makedirs') as mocked_makedirs:
|
patch(u'openlp.core.lib.os.makedirs') as mocked_makedirs:
|
||||||
# GIVEN: A directory to check and a mocked out os.makedirs and os.path.exists
|
# GIVEN: A directory to check and a mocked out os.makedirs and os.path.exists
|
||||||
directory_to_check = u'existing/directory'
|
directory_to_check = u'existing/directory'
|
||||||
|
|
||||||
|
@ -219,7 +226,7 @@ class TestLib(TestCase):
|
||||||
Test the build_icon() function with a resource URI
|
Test the build_icon() function with a resource URI
|
||||||
"""
|
"""
|
||||||
with patch(u'openlp.core.lib.QtGui') as MockedQtGui, \
|
with patch(u'openlp.core.lib.QtGui') as MockedQtGui, \
|
||||||
patch(u'openlp.core.lib.QtGui.QPixmap') as MockedQPixmap:
|
patch(u'openlp.core.lib.QtGui.QPixmap') as MockedQPixmap:
|
||||||
# GIVEN: A mocked QIcon and a mocked QPixmap
|
# GIVEN: A mocked QIcon and a mocked QPixmap
|
||||||
MockedQtGui.QIcon = MagicMock
|
MockedQtGui.QIcon = MagicMock
|
||||||
MockedQtGui.QIcon.Normal = 1
|
MockedQtGui.QIcon.Normal = 1
|
||||||
|
@ -261,9 +268,43 @@ class TestLib(TestCase):
|
||||||
mocked_byte_array.toBase64.assert_called_with()
|
mocked_byte_array.toBase64.assert_called_with()
|
||||||
assert result == u'base64mock', u'The result should be the return value of the mocked out base64 method'
|
assert result == u'base64mock', u'The result should be the return value of the mocked out base64 method'
|
||||||
|
|
||||||
|
def create_thumb_with_size_test(self):
|
||||||
|
"""
|
||||||
|
Test the create_thumb() function
|
||||||
|
"""
|
||||||
|
# GIVEN: An image to create a thumb of.
|
||||||
|
image_path = os.path.join(TEST_PATH, u'church.jpg')
|
||||||
|
thumb_path = os.path.join(TEST_PATH, u'church_thumb.jpg')
|
||||||
|
thumb_size = QtCore.QSize(10, 20)
|
||||||
|
|
||||||
|
# Remove the thumb so that the test actually tests if the thumb will be created. Maybe it was not deleted in the
|
||||||
|
# last test.
|
||||||
|
try:
|
||||||
|
os.remove(thumb_path)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Only continue when the thumb does not exist.
|
||||||
|
assert not os.path.exists(thumb_path), u'Test was not ran, because the thumb already exists.'
|
||||||
|
|
||||||
|
# WHEN: Create the thumb.
|
||||||
|
icon = create_thumb(image_path, thumb_path, size=thumb_size)
|
||||||
|
|
||||||
|
# THEN: Check if the thumb was created.
|
||||||
|
assert os.path.exists(thumb_path), u'Test was not ran, because the thumb already exists.'
|
||||||
|
assert isinstance(icon, QtGui.QIcon), u'The icon should be a QIcon.'
|
||||||
|
assert not icon.isNull(), u'The icon should not be null.'
|
||||||
|
assert QtGui.QImageReader(thumb_path).size() == thumb_size, u'The thumb should have the given size.'
|
||||||
|
|
||||||
|
# Remove the thumb so that the test actually tests if the thumb will be created.
|
||||||
|
try:
|
||||||
|
os.remove(thumb_path)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
def check_item_selected_true_test(self):
|
def check_item_selected_true_test(self):
|
||||||
"""
|
"""
|
||||||
Test that the check_item_selected() function returns True when there are selected indexes.
|
Test that the check_item_selected() function returns True when there are selected indexes
|
||||||
"""
|
"""
|
||||||
# GIVEN: A mocked out QtGui module and a list widget with selected indexes
|
# GIVEN: A mocked out QtGui module and a list widget with selected indexes
|
||||||
MockedQtGui = patch(u'openlp.core.lib.QtGui')
|
MockedQtGui = patch(u'openlp.core.lib.QtGui')
|
||||||
|
@ -423,7 +464,7 @@ class TestLib(TestCase):
|
||||||
|
|
||||||
def create_separated_list_qlocate_test(self):
|
def create_separated_list_qlocate_test(self):
|
||||||
"""
|
"""
|
||||||
Test the create_separated_list function using the Qt provided method.
|
Test the create_separated_list function using the Qt provided method
|
||||||
"""
|
"""
|
||||||
with patch(u'openlp.core.lib.Qt') as mocked_qt, \
|
with patch(u'openlp.core.lib.Qt') as mocked_qt, \
|
||||||
patch(u'openlp.core.lib.QtCore.QLocale.createSeparatedList') as mocked_createSeparatedList:
|
patch(u'openlp.core.lib.QtCore.QLocale.createSeparatedList') as mocked_createSeparatedList:
|
||||||
|
@ -442,7 +483,7 @@ class TestLib(TestCase):
|
||||||
|
|
||||||
def create_separated_list_empty_list_test(self):
|
def create_separated_list_empty_list_test(self):
|
||||||
"""
|
"""
|
||||||
Test the create_separated_list function with an empty list.
|
Test the create_separated_list function with an empty list
|
||||||
"""
|
"""
|
||||||
with patch(u'openlp.core.lib.Qt') as mocked_qt:
|
with patch(u'openlp.core.lib.Qt') as mocked_qt:
|
||||||
# GIVEN: An empty list and the mocked Qt module.
|
# GIVEN: An empty list and the mocked Qt module.
|
||||||
|
@ -458,7 +499,7 @@ class TestLib(TestCase):
|
||||||
|
|
||||||
def create_separated_list_with_one_item_test(self):
|
def create_separated_list_with_one_item_test(self):
|
||||||
"""
|
"""
|
||||||
Test the create_separated_list function with a list consisting of only one entry.
|
Test the create_separated_list function with a list consisting of only one entry
|
||||||
"""
|
"""
|
||||||
with patch(u'openlp.core.lib.Qt') as mocked_qt:
|
with patch(u'openlp.core.lib.Qt') as mocked_qt:
|
||||||
# GIVEN: A list with a string and the mocked Qt module.
|
# GIVEN: A list with a string and the mocked Qt module.
|
||||||
|
@ -474,7 +515,7 @@ class TestLib(TestCase):
|
||||||
|
|
||||||
def create_separated_list_with_two_items_test(self):
|
def create_separated_list_with_two_items_test(self):
|
||||||
"""
|
"""
|
||||||
Test the create_separated_list function with a list of two entries.
|
Test the create_separated_list function with a list of two entries
|
||||||
"""
|
"""
|
||||||
with patch(u'openlp.core.lib.Qt') as mocked_qt, patch(u'openlp.core.lib.translate') as mocked_translate:
|
with patch(u'openlp.core.lib.Qt') as mocked_qt, patch(u'openlp.core.lib.translate') as mocked_translate:
|
||||||
# GIVEN: A list of strings and the mocked Qt module.
|
# GIVEN: A list of strings and the mocked Qt module.
|
||||||
|
@ -491,7 +532,7 @@ class TestLib(TestCase):
|
||||||
|
|
||||||
def create_separated_list_with_three_items_test(self):
|
def create_separated_list_with_three_items_test(self):
|
||||||
"""
|
"""
|
||||||
Test the create_separated_list function with a list of three items.
|
Test the create_separated_list function with a list of three items
|
||||||
"""
|
"""
|
||||||
with patch(u'openlp.core.lib.Qt') as mocked_qt, patch(u'openlp.core.lib.translate') as mocked_translate:
|
with patch(u'openlp.core.lib.Qt') as mocked_qt, patch(u'openlp.core.lib.translate') as mocked_translate:
|
||||||
# GIVEN: A list with a string and the mocked Qt module.
|
# GIVEN: A list with a string and the mocked Qt module.
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue