forked from openlp/openlp
Merge from head.
This commit is contained in:
commit
04c1db2033
|
@ -10,3 +10,7 @@ openlp.org 2.0.e4*
|
|||
documentation/build/html
|
||||
documentation/build/doctrees
|
||||
*.log*
|
||||
dist
|
||||
OpenLP.egg-info
|
||||
build
|
||||
resources/innosetup/Output
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
recursive-include openlp *.py
|
||||
recursive-include openlp *.sqlite
|
||||
recursive-include openlp *.csv
|
||||
recursive-include documentation *
|
||||
recursive-include resources/forms *
|
||||
recursive-include resources/i18n *
|
||||
recursive-include resources/images *
|
||||
recursive-include scripts *.py
|
||||
include resources/*.desktop
|
||||
include copyright.txt
|
||||
include LICENSE
|
||||
include openlp/.version
|
|
@ -0,0 +1,19 @@
|
|||
# -*- mode: python -*-
|
||||
a = Analysis([os.path.join(HOMEPATH,'support\\_mountzlib.py'), os.path.join(HOMEPATH,'support\\useUnicode.py'), 'openlp.pyw'],
|
||||
pathex=['c:\\Documents and Settings\\raoul\\My Documents\\My Projects\\openlp\\pyinstaller'])
|
||||
pyz = PYZ(a.pure)
|
||||
exe = EXE(pyz,
|
||||
a.scripts,
|
||||
exclude_binaries=1,
|
||||
name=os.path.join('build\\pyi.win32\\OpenLP', 'OpenLP.exe'),
|
||||
debug=False,
|
||||
strip=False,
|
||||
upx=True,
|
||||
console=False , icon='resources\\images\\OpenLP.ico')
|
||||
coll = COLLECT( exe,
|
||||
a.binaries,
|
||||
a.zipfiles,
|
||||
a.datas,
|
||||
strip=False,
|
||||
upx=True,
|
||||
name=os.path.join('dist', 'OpenLP'))
|
53
openlp.pyw
53
openlp.pyw
|
@ -28,16 +28,17 @@ import os
|
|||
import sys
|
||||
import logging
|
||||
|
||||
from logging.handlers import RotatingFileHandler
|
||||
from logging import FileHandler
|
||||
from optparse import OptionParser
|
||||
from PyQt4 import QtCore, QtGui
|
||||
|
||||
log = logging.getLogger()
|
||||
|
||||
import openlp
|
||||
from openlp.core.lib import Receiver, str_to_bool
|
||||
from openlp.core.resources import qInitResources
|
||||
from openlp.core.ui import MainWindow, SplashScreen
|
||||
from openlp.core.utils import ConfigHelper
|
||||
|
||||
log = logging.getLogger()
|
||||
from openlp.core.ui import MainWindow, SplashScreen, ScreenList
|
||||
from openlp.core.utils import AppLocation, ConfigHelper
|
||||
|
||||
application_stylesheet = u"""
|
||||
QMainWindow::separator
|
||||
|
@ -47,9 +48,11 @@ QMainWindow::separator
|
|||
|
||||
QDockWidget::title
|
||||
{
|
||||
border: none;
|
||||
/*background: palette(dark);*/
|
||||
border: 1px solid palette(dark);
|
||||
padding-left: 5px;
|
||||
padding-top: 3px;
|
||||
padding-top: 2px;
|
||||
margin: 1px 0;
|
||||
}
|
||||
|
||||
QToolBar
|
||||
|
@ -65,16 +68,21 @@ class OpenLP(QtGui.QApplication):
|
|||
The core application class. This class inherits from Qt's QApplication
|
||||
class in order to provide the core of the application.
|
||||
"""
|
||||
global log
|
||||
log.info(u'OpenLP Application Loaded')
|
||||
|
||||
def notify(self, obj, evt):
|
||||
#TODO needed for presentation exceptions
|
||||
return QtGui.QApplication.notify(self, obj, evt)
|
||||
|
||||
def run(self):
|
||||
"""
|
||||
Run the OpenLP application.
|
||||
"""
|
||||
#Load and store current Application Version
|
||||
filepath = os.path.split(os.path.abspath(__file__))[0]
|
||||
filepath = os.path.abspath(os.path.join(filepath, u'version.txt'))
|
||||
filepath = AppLocation.get_directory(AppLocation.AppDir)
|
||||
if not hasattr(sys, u'frozen'):
|
||||
filepath = os.path.join(filepath, u'openlp')
|
||||
filepath = os.path.join(filepath, u'.version')
|
||||
fversion = None
|
||||
try:
|
||||
fversion = open(filepath, u'r')
|
||||
|
@ -91,9 +99,9 @@ class OpenLP(QtGui.QApplication):
|
|||
app_version[u'version'], app_version[u'build']))
|
||||
except:
|
||||
app_version = {
|
||||
u'full': u'1.9.0-000',
|
||||
u'full': u'1.9.0-bzr000',
|
||||
u'version': u'1.9.0',
|
||||
u'build': u'000'
|
||||
u'build': u'bzr000'
|
||||
}
|
||||
finally:
|
||||
if fversion:
|
||||
|
@ -117,10 +125,10 @@ class OpenLP(QtGui.QApplication):
|
|||
self.splash.show()
|
||||
# make sure Qt really display the splash screen
|
||||
self.processEvents()
|
||||
screens = []
|
||||
screens = ScreenList()
|
||||
# Decide how many screens we have and their size
|
||||
for screen in xrange(0, self.desktop().numScreens()):
|
||||
screens.append({u'number': screen,
|
||||
screens.add_screen({u'number': screen,
|
||||
u'size': self.desktop().availableGeometry(screen),
|
||||
u'primary': (self.desktop().primaryScreen() == screen)})
|
||||
log.info(u'Screen %d found with resolution %s',
|
||||
|
@ -131,7 +139,8 @@ class OpenLP(QtGui.QApplication):
|
|||
if show_splash:
|
||||
# now kill the splashscreen
|
||||
self.splash.finish(self.mainWindow)
|
||||
self.mainWindow.versionCheck()
|
||||
self.mainWindow.repaint()
|
||||
self.mainWindow.versionThread()
|
||||
return self.exec_()
|
||||
|
||||
def main():
|
||||
|
@ -143,7 +152,7 @@ def main():
|
|||
usage = u'Usage: %prog [options] [qt-options]'
|
||||
parser = OptionParser(usage=usage)
|
||||
parser.add_option("-l", "--log-level", dest="loglevel",
|
||||
default="info", metavar="LEVEL",
|
||||
default="warning", metavar="LEVEL",
|
||||
help="Set logging to LEVEL level. Valid values are "
|
||||
"\"debug\", \"info\", \"warning\".")
|
||||
parser.add_option("-p", "--portable", dest="portable",
|
||||
|
@ -153,10 +162,13 @@ def main():
|
|||
parser.add_option("-s", "--style", dest="style",
|
||||
help="Set the Qt4 style (passed directly to Qt4).")
|
||||
# Set up logging
|
||||
filename = u'openlp.log'
|
||||
logfile = RotatingFileHandler(filename, maxBytes=200000, backupCount=5)
|
||||
log_path = AppLocation.get_directory(AppLocation.ConfigDir)
|
||||
if not os.path.exists(log_path):
|
||||
os.makedirs(log_path)
|
||||
filename = os.path.join(log_path, u'openlp.log')
|
||||
logfile = FileHandler(filename, u'w')
|
||||
logfile.setFormatter(logging.Formatter(
|
||||
u'%(asctime)s %(name)-15s %(levelname)-8s %(message)s'))
|
||||
u'%(asctime)s %(name)-20s %(levelname)-8s %(message)s'))
|
||||
log.addHandler(logfile)
|
||||
logging.addLevelName(15, u'Timer')
|
||||
# Parse command line options and deal with them.
|
||||
|
@ -164,6 +176,7 @@ def main():
|
|||
qt_args = []
|
||||
if options.loglevel.lower() in ['d', 'debug']:
|
||||
log.setLevel(logging.DEBUG)
|
||||
print 'Logging to:', filename
|
||||
elif options.loglevel.lower() in ['w', 'warning']:
|
||||
log.setLevel(logging.WARNING)
|
||||
else:
|
||||
|
@ -182,4 +195,4 @@ if __name__ == u'__main__':
|
|||
"""
|
||||
Instantiate and run the application.
|
||||
"""
|
||||
main()
|
||||
main()
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
1.9.0-bzr722
|
|
@ -136,6 +136,26 @@ def contextMenuSeparator(base):
|
|||
action.setSeparator(True)
|
||||
return action
|
||||
|
||||
def resize_image(image, width, height):
|
||||
"""
|
||||
Resize an image to fit on the current screen.
|
||||
|
||||
``image``
|
||||
The image to resize.
|
||||
"""
|
||||
preview = QtGui.QImage(image)
|
||||
preview = preview.scaled(width, height, QtCore.Qt.KeepAspectRatio,
|
||||
QtCore.Qt.SmoothTransformation)
|
||||
realw = preview.width()
|
||||
realh = preview.height()
|
||||
# and move it to the centre of the preview space
|
||||
newImage = QtGui.QImage(width, height, QtGui.QImage.Format_ARGB32_Premultiplied)
|
||||
newImage.fill(QtCore.Qt.black)
|
||||
painter = QtGui.QPainter(newImage)
|
||||
painter.drawImage((width - realw) / 2, (height - realh) / 2, preview)
|
||||
return newImage
|
||||
|
||||
|
||||
class ThemeLevel(object):
|
||||
Global = 1
|
||||
Service = 2
|
||||
|
@ -160,6 +180,3 @@ from renderer import Renderer
|
|||
from rendermanager import RenderManager
|
||||
from mediamanageritem import MediaManagerItem
|
||||
from baselistwithdnd import BaseListWithDnD
|
||||
|
||||
#__all__ = [ 'translate', 'get_text_file_string', 'str_to_bool',
|
||||
# 'contextMenuAction', 'contextMenuSeparator', 'ServiceItem']
|
|
@ -32,6 +32,7 @@ class BaseListWithDnD(QtGui.QListWidget):
|
|||
|
||||
def __init__(self, parent=None):
|
||||
QtGui.QListWidget.__init__(self, parent)
|
||||
self.parent = parent
|
||||
# this must be set by the class which is inheriting
|
||||
assert(self.PluginName)
|
||||
|
||||
|
@ -47,4 +48,5 @@ class BaseListWithDnD(QtGui.QListWidget):
|
|||
mimeData = QtCore.QMimeData()
|
||||
drag.setMimeData(mimeData)
|
||||
mimeData.setText(self.PluginName)
|
||||
dropAction = drag.start(QtCore.Qt.CopyAction)
|
||||
dropAction = drag.start(QtCore.Qt.CopyAction)
|
||||
|
||||
|
|
|
@ -27,6 +27,8 @@ import logging
|
|||
|
||||
from PyQt4 import QtGui
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
class OpenLPDockWidget(QtGui.QDockWidget):
|
||||
"""
|
||||
Custom DockWidget class to handle events
|
||||
|
@ -40,10 +42,9 @@ class OpenLPDockWidget(QtGui.QDockWidget):
|
|||
if name:
|
||||
self.setObjectName(name)
|
||||
self.setFloating(False)
|
||||
self.log = logging.getLogger(u'OpenLPDockWidget')
|
||||
self.log.debug(u'Init done')
|
||||
log.debug(u'Init done')
|
||||
|
||||
def closeEvent(self, event):
|
||||
self.parent.settingsmanager.setUIItemVisibility(
|
||||
self.objectName(), False)
|
||||
event.accept()
|
||||
event.accept()
|
||||
|
|
|
@ -27,6 +27,8 @@ import logging
|
|||
|
||||
from PyQt4 import QtCore
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
class EventReceiver(QtCore.QObject):
|
||||
"""
|
||||
Class to allow events to be passed from different parts of the
|
||||
|
@ -104,10 +106,10 @@ class EventReceiver(QtCore.QObject):
|
|||
``remote_edit_clear``
|
||||
Informs all components that remote edit has been aborted.
|
||||
|
||||
"""
|
||||
global log
|
||||
log = logging.getLogger(u'EventReceiver')
|
||||
``presentation types``
|
||||
Informs all components of the presentation types supported.
|
||||
|
||||
"""
|
||||
def __init__(self):
|
||||
"""
|
||||
Initialise the event receiver, calling the parent constructor.
|
||||
|
@ -161,4 +163,5 @@ class Receiver():
|
|||
"""
|
||||
Get the global ``eventreceiver`` instance.
|
||||
"""
|
||||
return Receiver.eventreceiver
|
||||
return Receiver.eventreceiver
|
||||
|
||||
|
|
|
@ -32,6 +32,8 @@ from openlp.core.lib.toolbar import *
|
|||
from openlp.core.lib import contextMenuAction, contextMenuSeparator
|
||||
from serviceitem import ServiceItem
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
class MediaManagerItem(QtGui.QWidget):
|
||||
"""
|
||||
MediaManagerItem is a helper widget for plugins.
|
||||
|
@ -92,9 +94,6 @@ class MediaManagerItem(QtGui.QWidget):
|
|||
method is not defined, a default will be used (treat the
|
||||
filename as an image).
|
||||
"""
|
||||
|
||||
global log
|
||||
log = logging.getLogger(u'MediaManagerItem')
|
||||
log.info(u'Media Item loaded')
|
||||
|
||||
def __init__(self, parent=None, icon=None, title=None):
|
||||
|
@ -253,7 +252,7 @@ class MediaManagerItem(QtGui.QWidget):
|
|||
|
||||
def addListViewToToolBar(self):
|
||||
#Add the List widget
|
||||
self.ListView = self.ListViewWithDnD_class()
|
||||
self.ListView = self.ListViewWithDnD_class(self)
|
||||
self.ListView.uniformItemSizes = True
|
||||
self.ListView.setGeometry(QtCore.QRect(10, 100, 256, 591))
|
||||
self.ListView.setSpacing(1)
|
||||
|
@ -315,7 +314,7 @@ class MediaManagerItem(QtGui.QWidget):
|
|||
self, self.OnNewPrompt,
|
||||
self.parent.config.get_last_dir(), self.OnNewFileMasks)
|
||||
log.info(u'New files(s)%s', unicode(files))
|
||||
if len(files) > 0:
|
||||
if files:
|
||||
self.loadList(files)
|
||||
dir, filename = os.path.split(unicode(files[0]))
|
||||
self.parent.config.set_last_dir(dir)
|
||||
|
@ -400,4 +399,4 @@ class MediaManagerItem(QtGui.QWidget):
|
|||
if self.generateSlideData(service_item):
|
||||
return service_item
|
||||
else:
|
||||
return None
|
||||
return None
|
||||
|
|
|
@ -28,6 +28,8 @@ from PyQt4 import QtCore
|
|||
|
||||
from openlp.core.lib import PluginConfig, Receiver
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
class PluginStatus(object):
|
||||
"""
|
||||
Defines the status of the plugin
|
||||
|
@ -88,8 +90,6 @@ class Plugin(QtCore.QObject):
|
|||
Used in the plugin manager, when a person clicks on the 'About' button.
|
||||
|
||||
"""
|
||||
global log
|
||||
log = logging.getLogger(u'Plugin')
|
||||
log.info(u'loaded')
|
||||
|
||||
def __init__(self, name, version=None, plugin_helpers=None):
|
||||
|
@ -127,6 +127,7 @@ class Plugin(QtCore.QObject):
|
|||
self.service_manager = plugin_helpers[u'service']
|
||||
self.settings = plugin_helpers[u'settings']
|
||||
self.mediadock = plugin_helpers[u'toolbox']
|
||||
self.maindisplay = plugin_helpers[u'maindisplay']
|
||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||
QtCore.SIGNAL(u'%s_add_service_item' % self.name),
|
||||
self.process_add_service_event)
|
||||
|
@ -252,4 +253,10 @@ class Plugin(QtCore.QObject):
|
|||
if self.media_item:
|
||||
self.mediadock.insert_dock(self.media_item, self.icon, self.weight)
|
||||
if self.settings_tab:
|
||||
self.settings.insertTab(self.settings_tab, self.weight)
|
||||
self.settings.insertTab(self.settings_tab, self.weight)
|
||||
|
||||
def can_delete_theme(self, theme):
|
||||
"""
|
||||
Called to ask the plugin if a theme can be deleted
|
||||
"""
|
||||
return True
|
||||
|
|
|
@ -29,13 +29,13 @@ import logging
|
|||
|
||||
from openlp.core.lib import Plugin, PluginStatus
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
class PluginManager(object):
|
||||
"""
|
||||
This is the Plugin manager, which loads all the plugins,
|
||||
and executes all the hooks, as and when necessary.
|
||||
"""
|
||||
global log
|
||||
log = logging.getLogger(u'PluginMgr')
|
||||
log.info(u'Plugin manager loaded')
|
||||
|
||||
def __init__(self, dir):
|
||||
|
@ -54,7 +54,7 @@ class PluginManager(object):
|
|||
log.debug(u'Base path %s ', self.basepath)
|
||||
self.plugins = []
|
||||
# this has to happen after the UI is sorted self.find_plugins(dir)
|
||||
log.info(u'Plugin manager done init')
|
||||
log.info(u'Plugin manager Initialised')
|
||||
|
||||
def find_plugins(self, dir, plugin_helpers):
|
||||
"""
|
||||
|
@ -77,7 +77,7 @@ class PluginManager(object):
|
|||
if name.endswith(u'.py') and not name.startswith(u'__'):
|
||||
path = os.path.abspath(os.path.join(root, name))
|
||||
thisdepth = len(path.split(os.sep))
|
||||
if thisdepth-startdepth > 2:
|
||||
if thisdepth - startdepth > 2:
|
||||
# skip anything lower down
|
||||
continue
|
||||
modulename, pyext = os.path.splitext(path)
|
||||
|
@ -101,7 +101,7 @@ class PluginManager(object):
|
|||
log.debug(u'Loaded plugin %s with helpers', unicode(p))
|
||||
plugin_objects.append(plugin)
|
||||
except TypeError:
|
||||
log.error(u'loaded plugin %s has no helpers', unicode(p))
|
||||
log.exception(u'loaded plugin %s has no helpers', unicode(p))
|
||||
plugins_list = sorted(plugin_objects, self.order_by_weight)
|
||||
for plugin in plugins_list:
|
||||
if plugin.check_pre_conditions():
|
||||
|
@ -200,6 +200,7 @@ class PluginManager(object):
|
|||
% (plugin.name, plugin.is_active()))
|
||||
if plugin.is_active():
|
||||
plugin.initialise()
|
||||
log.info(u'Initialisation Complete for %s ' % plugin.name)
|
||||
if not plugin.is_active():
|
||||
plugin.remove_toolbox_item()
|
||||
|
||||
|
@ -211,4 +212,5 @@ class PluginManager(object):
|
|||
log.info(u'finalising plugins')
|
||||
for plugin in self.plugins:
|
||||
if plugin.is_active():
|
||||
plugin.finalise()
|
||||
plugin.finalise()
|
||||
log.info(u'Finalisation Complete for %s ' % plugin.name)
|
||||
|
|
|
@ -26,14 +26,15 @@
|
|||
import logging
|
||||
|
||||
from PyQt4 import QtGui, QtCore
|
||||
from openlp.core.lib import resize_image
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
class Renderer(object):
|
||||
"""
|
||||
Genarates a pixmap image of a array of text. The Text is formatted to
|
||||
make sure it fits on the screen and if not extra frames are generated.
|
||||
"""
|
||||
global log
|
||||
log = logging.getLogger(u'Renderer')
|
||||
log.info(u'Renderer Loaded')
|
||||
|
||||
def __init__(self):
|
||||
|
@ -41,7 +42,7 @@ class Renderer(object):
|
|||
Initialise the renderer.
|
||||
"""
|
||||
self._rect = None
|
||||
self._debug = 0
|
||||
self._debug = False
|
||||
self._right_margin = 64 # the amount of right indent
|
||||
self._display_shadow_size_footer = 0
|
||||
self._display_outline_size_footer = 0
|
||||
|
@ -90,31 +91,9 @@ class Renderer(object):
|
|||
log.debug(u'set bg image %s', filename)
|
||||
self._bg_image_filename = unicode(filename)
|
||||
if self._frame:
|
||||
self.scale_bg_image()
|
||||
|
||||
def scale_bg_image(self):
|
||||
"""
|
||||
Scale the background image to fit the screen.
|
||||
"""
|
||||
assert self._frame
|
||||
preview = QtGui.QImage(self._bg_image_filename)
|
||||
width = self._frame.width()
|
||||
height = self._frame.height()
|
||||
preview = preview.scaled(width, height, QtCore.Qt.KeepAspectRatio,
|
||||
QtCore.Qt.SmoothTransformation)
|
||||
realwidth = preview.width()
|
||||
realheight = preview.height()
|
||||
# and move it to the centre of the preview space
|
||||
self.bg_image = QtGui.QImage(width, height,
|
||||
QtGui.QImage.Format_ARGB32_Premultiplied)
|
||||
self.bg_image.fill(QtCore.Qt.black)
|
||||
painter = QtGui.QPainter()
|
||||
painter.begin(self.bg_image)
|
||||
self.background_offsetx = (width - realwidth) / 2
|
||||
self.background_offsety = (height - realheight) / 2
|
||||
painter.drawImage(self.background_offsetx,
|
||||
self.background_offsety, preview)
|
||||
painter.end()
|
||||
self.bg_image = resize_image(self._bg_image_filename,
|
||||
self._frame.width(),
|
||||
self._frame.height())
|
||||
|
||||
def set_frame_dest(self, frame_width, frame_height, preview=False):
|
||||
"""
|
||||
|
@ -138,7 +117,9 @@ class Renderer(object):
|
|||
self._frameOp = QtGui.QImage(frame_width, frame_height,
|
||||
QtGui.QImage.Format_ARGB32_Premultiplied)
|
||||
if self._bg_image_filename and not self.bg_image:
|
||||
self.scale_bg_image()
|
||||
self.bg_image = resize_image(self._bg_image_filename,
|
||||
self._frame.width(),
|
||||
self._frame.height())
|
||||
if self.bg_frame is None:
|
||||
self._generate_background_frame()
|
||||
|
||||
|
@ -167,17 +148,22 @@ class Renderer(object):
|
|||
|
||||
def pre_render_text(self, text):
|
||||
metrics = QtGui.QFontMetrics(self.mainFont)
|
||||
#take the width work out approx how many characters and add 50%
|
||||
#work out line width
|
||||
line_width = self._rect.width() - self._right_margin
|
||||
#number of lines on a page - adjust for rounding up.
|
||||
page_length = int(self._rect.height() / metrics.height() - 2 ) - 1
|
||||
line_height = metrics.height()
|
||||
if self._theme.display_shadow:
|
||||
line_height += int(self._theme.display_shadow_size)
|
||||
if self._theme.display_outline:
|
||||
# pixels top/bottom
|
||||
line_height += 2 * int(self._theme.display_outline_size)
|
||||
page_length = int(self._rect.height() / line_height )
|
||||
#Average number of characters in line
|
||||
ave_line_width = line_width / metrics.averageCharWidth()
|
||||
#Maximum size of a character
|
||||
max_char_width = metrics.maxWidth()
|
||||
#Min size of a character
|
||||
min_char_width = metrics.width(u'i')
|
||||
char_per_line = line_width / min_char_width
|
||||
#Max characters pre line based on min size of a character
|
||||
char_per_line = line_width / metrics.width(u'i')
|
||||
log.debug(u'Page Length area height %s , metrics %s , lines %s' %
|
||||
(int(self._rect.height()), metrics.height(), page_length ))
|
||||
split_pages = []
|
||||
|
@ -188,7 +174,7 @@ class Renderer(object):
|
|||
#Must be a blank line so keep it.
|
||||
if len(line) == 0:
|
||||
line = u' '
|
||||
while len(line) > 0:
|
||||
while line:
|
||||
pos = char_per_line
|
||||
split_text = line[:pos]
|
||||
#line needs splitting
|
||||
|
@ -213,7 +199,7 @@ class Renderer(object):
|
|||
split_lines.append(split_text)
|
||||
line = line[pos:].lstrip()
|
||||
#if we have more text add up to 10 spaces on the front.
|
||||
if len(line) > 0 and self._theme.font_main_indentation > 0:
|
||||
if line and self._theme.font_main_indentation > 0:
|
||||
line = u'%s%s' % \
|
||||
(u' '[:int(self._theme.font_main_indentation)], line)
|
||||
#Text fits in a line now
|
||||
|
@ -224,7 +210,7 @@ class Renderer(object):
|
|||
len(page) == page_length:
|
||||
split_pages.append(page)
|
||||
page = []
|
||||
if len(page) > 0 and page != u' ':
|
||||
if page and page != u' ':
|
||||
split_pages.append(page)
|
||||
return split_pages
|
||||
|
||||
|
@ -276,8 +262,13 @@ class Renderer(object):
|
|||
Results are cached for performance reasons.
|
||||
"""
|
||||
assert(self._theme)
|
||||
self.bg_frame = QtGui.QImage(self._frame.width(), self._frame.height(),
|
||||
QtGui.QImage.Format_ARGB32_Premultiplied)
|
||||
if self._theme.background_mode == u'transparent':
|
||||
self.bg_frame = \
|
||||
QtGui.QPixmap(self._frame.width(), self._frame.height())
|
||||
self.bg_frame.fill(QtCore.Qt.transparent)
|
||||
else:
|
||||
self.bg_frame = QtGui.QImage(self._frame.width(), self._frame.height(),
|
||||
QtGui.QImage.Format_ARGB32_Premultiplied)
|
||||
log.debug(u'render background %s start', self._theme.background_type)
|
||||
painter = QtGui.QPainter()
|
||||
painter.begin(self.bg_frame)
|
||||
|
@ -415,13 +406,21 @@ class Renderer(object):
|
|||
Defaults to *False*. Whether or not this is a live screen.
|
||||
"""
|
||||
x, y = tlcorner
|
||||
maxx = self._rect.width();
|
||||
maxy = self._rect.height();
|
||||
maxx = self._rect.width()
|
||||
maxy = self._rect.height()
|
||||
lines = []
|
||||
lines.append(line)
|
||||
startx = x
|
||||
starty = y
|
||||
rightextent = None
|
||||
self.painter = QtGui.QPainter()
|
||||
self.painter.begin(self._frame)
|
||||
self.painter.setRenderHint(QtGui.QPainter.Antialiasing)
|
||||
if self._theme.display_slideTransition:
|
||||
self.painter2 = QtGui.QPainter()
|
||||
self.painter2.begin(self._frameOp)
|
||||
self.painter2.setRenderHint(QtGui.QPainter.Antialiasing)
|
||||
self.painter2.setOpacity(0.7)
|
||||
# dont allow alignment messing with footers
|
||||
if footer:
|
||||
align = 0
|
||||
|
@ -459,7 +458,7 @@ class Renderer(object):
|
|||
x = maxx - w
|
||||
# centre
|
||||
elif align == 2:
|
||||
x = (maxx - w) / 2;
|
||||
x = (maxx - w) / 2
|
||||
rightextent = x + w
|
||||
if live:
|
||||
# now draw the text, and any outlines/shadows
|
||||
|
@ -467,49 +466,21 @@ class Renderer(object):
|
|||
self._get_extent_and_render(line, footer,
|
||||
tlcorner=(x + display_shadow_size, y + display_shadow_size),
|
||||
draw=True, color = self._theme.display_shadow_color)
|
||||
if self._theme.display_outline:
|
||||
self._get_extent_and_render(line, footer,
|
||||
(x + display_outline_size, y), draw=True,
|
||||
color = self._theme.display_outline_color)
|
||||
self._get_extent_and_render(line, footer,
|
||||
(x, y + display_outline_size), draw=True,
|
||||
color = self._theme.display_outline_color)
|
||||
self._get_extent_and_render(line, footer,
|
||||
(x, y - display_outline_size), draw=True,
|
||||
color = self._theme.display_outline_color)
|
||||
self._get_extent_and_render(line, footer,
|
||||
(x - display_outline_size, y), draw=True,
|
||||
color = self._theme.display_outline_color)
|
||||
if display_outline_size > 1:
|
||||
self._get_extent_and_render(line, footer,
|
||||
(x + display_outline_size, y + display_outline_size),
|
||||
draw=True,
|
||||
color = self._theme.display_outline_color)
|
||||
self._get_extent_and_render(line, footer,
|
||||
(x - display_outline_size, y + display_outline_size),
|
||||
draw=True,
|
||||
color = self._theme.display_outline_color)
|
||||
self._get_extent_and_render(line, footer,
|
||||
(x + display_outline_size, y - display_outline_size),
|
||||
draw=True,
|
||||
color = self._theme.display_outline_color)
|
||||
self._get_extent_and_render(line, footer,
|
||||
(x - display_outline_size, y - display_outline_size),
|
||||
draw=True,
|
||||
color = self._theme.display_outline_color)
|
||||
self._get_extent_and_render(line, footer,tlcorner=(x, y),
|
||||
draw=True)
|
||||
self._get_extent_and_render(line, footer, tlcorner=(x, y), draw=True,
|
||||
outline_size=display_outline_size,
|
||||
outline_color=self._theme.display_outline_color)
|
||||
y += h
|
||||
if linenum == 0:
|
||||
self._first_line_right_extent = rightextent
|
||||
# draw a box around the text - debug only
|
||||
|
||||
if self._debug:
|
||||
painter = QtGui.QPainter()
|
||||
painter.begin(self._frame)
|
||||
painter.setPen(QtGui.QPen(QtGui.QColor(0,255,0)))
|
||||
painter.drawRect(startx, starty, rightextent-startx, y-starty)
|
||||
painter.end()
|
||||
self.painter.setPen(QtGui.QPen(QtGui.QColor(0,255,0)))
|
||||
self.painter.drawRect(startx, starty, rightextent-startx, y-starty)
|
||||
brcorner = (rightextent, y)
|
||||
self.painter.end()
|
||||
if self._theme.display_slideTransition:
|
||||
self.painter2.end()
|
||||
return brcorner
|
||||
|
||||
def _set_theme_font(self):
|
||||
|
@ -519,6 +490,7 @@ class Renderer(object):
|
|||
footer_weight = 50
|
||||
if self._theme.font_footer_weight == u'Bold':
|
||||
footer_weight = 75
|
||||
#TODO Add myfont.setPixelSize((screen_height / 100) * font_size)
|
||||
self.footerFont = QtGui.QFont(self._theme.font_footer_name,
|
||||
self._theme.font_footer_proportion, # size
|
||||
footer_weight, # weight
|
||||
|
@ -534,7 +506,7 @@ class Renderer(object):
|
|||
self.mainFont.setPixelSize(self._theme.font_main_proportion)
|
||||
|
||||
def _get_extent_and_render(self, line, footer, tlcorner=(0, 0), draw=False,
|
||||
color=None):
|
||||
color=None, outline_size=None, outline_color=None):
|
||||
"""
|
||||
Find bounding box of text - as render_single_line. If draw is set,
|
||||
actually draw the text to the current DC as well return width and
|
||||
|
@ -556,45 +528,42 @@ class Renderer(object):
|
|||
Defaults to *None*. The colour to draw with.
|
||||
"""
|
||||
# setup defaults
|
||||
painter = QtGui.QPainter()
|
||||
painter.begin(self._frame)
|
||||
painter.setRenderHint(QtGui.QPainter.Antialiasing);
|
||||
if footer :
|
||||
font = self.footerFont
|
||||
else:
|
||||
font = self.mainFont
|
||||
painter.setFont(font)
|
||||
if color is None:
|
||||
if footer:
|
||||
painter.setPen(QtGui.QColor(self._theme.font_footer_color))
|
||||
else:
|
||||
painter.setPen(QtGui.QColor(self._theme.font_main_color))
|
||||
else:
|
||||
painter.setPen(QtGui.QColor(color))
|
||||
x, y = tlcorner
|
||||
metrics = QtGui.QFontMetrics(font)
|
||||
w = metrics.width(line)
|
||||
h = metrics.height() - 2
|
||||
h = metrics.height()
|
||||
if draw:
|
||||
painter.drawText(x, y + metrics.ascent(), line)
|
||||
painter.end()
|
||||
if self._theme.display_slideTransition:
|
||||
# Print 2nd image with 70% weight
|
||||
painter = QtGui.QPainter()
|
||||
painter.begin(self._frameOp)
|
||||
painter.setRenderHint(QtGui.QPainter.Antialiasing);
|
||||
painter.setOpacity(0.7)
|
||||
painter.setFont(font)
|
||||
self.painter.setFont(font)
|
||||
if color is None:
|
||||
if footer:
|
||||
painter.setPen(QtGui.QColor(self._theme.font_footer_color))
|
||||
pen = QtGui.QColor(self._theme.font_footer_color)
|
||||
else:
|
||||
painter.setPen(QtGui.QColor(self._theme.font_main_color))
|
||||
pen = QtGui.QColor(self._theme.font_main_color)
|
||||
else:
|
||||
painter.setPen(QtGui.QColor(color))
|
||||
if draw:
|
||||
painter.drawText(x, y + metrics.ascent(), line)
|
||||
painter.end()
|
||||
pen = QtGui.QColor(color)
|
||||
x, y = tlcorner
|
||||
if outline_size:
|
||||
path = QtGui.QPainterPath()
|
||||
path.addText(QtCore.QPointF(x, y + metrics.ascent()), font, line)
|
||||
self.painter.setBrush(self.painter.pen().brush())
|
||||
self.painter.setPen(QtGui.QPen(QtGui.QColor(outline_color), outline_size))
|
||||
self.painter.drawPath(path)
|
||||
self.painter.setPen(pen)
|
||||
self.painter.drawText(x, y + metrics.ascent(), line)
|
||||
if self._theme.display_slideTransition:
|
||||
# Print 2nd image with 70% weight
|
||||
if outline_size:
|
||||
path = QtGui.QPainterPath()
|
||||
path.addText(QtCore.QPointF(x, y + metrics.ascent()), font, line)
|
||||
self.painter2.setBrush(self.painter2.pen().brush())
|
||||
self.painter2.setPen(QtGui.QPen(QtGui.QColor(outline_color), outline_size))
|
||||
self.painter2.drawPath(path)
|
||||
self.painter2.setFont(font)
|
||||
self.painter2.setPen(pen)
|
||||
self.painter2.drawText(x, y + metrics.ascent(), line)
|
||||
return (w, h)
|
||||
|
||||
def snoop_Image(self, image, image2=None):
|
||||
|
@ -609,4 +578,4 @@ class Renderer(object):
|
|||
"""
|
||||
image.save(u'renderer.png', u'png')
|
||||
if image2:
|
||||
image2.save(u'renderer2.png', u'png')
|
||||
image2.save(u'renderer2.png', u'png')
|
||||
|
|
|
@ -25,11 +25,13 @@
|
|||
|
||||
import logging
|
||||
|
||||
from PyQt4 import QtGui, QtCore
|
||||
from PyQt4 import QtCore
|
||||
|
||||
from renderer import Renderer
|
||||
from openlp.core.lib import ThemeLevel
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
class RenderManager(object):
|
||||
"""
|
||||
Class to pull all Renderer interactions into one place. The plugins will
|
||||
|
@ -39,37 +41,29 @@ class RenderManager(object):
|
|||
``theme_manager``
|
||||
The ThemeManager instance, used to get the current theme details.
|
||||
|
||||
``screen_list``
|
||||
The list of screens available.
|
||||
``screens``
|
||||
Contains information about the Screens.
|
||||
|
||||
``screen_number``
|
||||
Defaults to *0*. The index of the output/display screen.
|
||||
"""
|
||||
global log
|
||||
log = logging.getLogger(u'RenderManager')
|
||||
log.info(u'RenderManager Loaded')
|
||||
|
||||
def __init__(self, theme_manager, screen_list, screen_number=0):
|
||||
def __init__(self, theme_manager, screens, screen_number=0):
|
||||
"""
|
||||
Initialise the render manager.
|
||||
"""
|
||||
log.debug(u'Initilisation started')
|
||||
self.screen_list = screen_list
|
||||
self.screens = screens
|
||||
self.theme_manager = theme_manager
|
||||
self.displays = len(screen_list)
|
||||
if (screen_number + 1) > len(screen_list):
|
||||
self.current_display = 0
|
||||
else:
|
||||
self.current_display = screen_number
|
||||
self.renderer = Renderer()
|
||||
self.calculate_default(self.screen_list[self.current_display][u'size'])
|
||||
self.screens.set_current_display(screen_number)
|
||||
self.calculate_default(self.screens.current[u'size'])
|
||||
self.theme = u''
|
||||
self.service_theme = u''
|
||||
self.theme_level = u''
|
||||
self.override_background = None
|
||||
self.themedata = None
|
||||
self.save_bg_frame = None
|
||||
self.override_background_changed = False
|
||||
|
||||
def update_display(self, screen_number):
|
||||
"""
|
||||
|
@ -79,10 +73,8 @@ class RenderManager(object):
|
|||
The updated index of the output/display screen.
|
||||
"""
|
||||
log.debug(u'Update Display')
|
||||
if self.current_display != screen_number:
|
||||
self.current_display = screen_number
|
||||
self.calculate_default(
|
||||
self.screen_list[self.current_display][u'size'])
|
||||
self.calculate_default(self.screens.current[u'size'])
|
||||
self.renderer.bg_frame = None
|
||||
|
||||
def set_global_theme(self, global_theme, theme_level=ThemeLevel.Global):
|
||||
"""
|
||||
|
@ -137,31 +129,14 @@ class RenderManager(object):
|
|||
if self.theme != self.renderer.theme_name or self.themedata is None:
|
||||
log.debug(u'theme is now %s', self.theme)
|
||||
self.themedata = self.theme_manager.getThemeData(self.theme)
|
||||
self.calculate_default(
|
||||
self.screen_list[self.current_display][u'size'])
|
||||
self.calculate_default(self.screens.current[u'size'])
|
||||
self.renderer.set_theme(self.themedata)
|
||||
self.build_text_rectangle(self.themedata)
|
||||
#Replace the backgrount image from renderer with one from image
|
||||
if self.override_background:
|
||||
if self.save_bg_frame is None:
|
||||
self.save_bg_frame = self.renderer.bg_frame
|
||||
if self.override_background_changed:
|
||||
self.renderer.bg_frame = self.resize_image(
|
||||
self.override_background)
|
||||
self.override_background_changed = False
|
||||
else:
|
||||
if self.override_background_changed:
|
||||
self.renderer.bg_frame = self.resize_image(
|
||||
self.override_background)
|
||||
self.override_background_changed = False
|
||||
if self.save_bg_frame:
|
||||
self.renderer.bg_frame = self.save_bg_frame
|
||||
self.save_bg_frame = None
|
||||
|
||||
def build_text_rectangle(self, theme):
|
||||
"""
|
||||
Builds a text block using the settings in ``theme``.
|
||||
One is needed per slide
|
||||
Builds a text block using the settings in ``theme``
|
||||
and the size of the display screen.height.
|
||||
|
||||
``theme``
|
||||
The theme to build a text block for.
|
||||
|
@ -170,14 +145,14 @@ class RenderManager(object):
|
|||
main_rect = None
|
||||
footer_rect = None
|
||||
if not theme.font_main_override:
|
||||
main_rect = QtCore.QRect(10, 0, self.width - 1,
|
||||
self.footer_start - 20)
|
||||
main_rect = QtCore.QRect(10, 0,
|
||||
self.width - 1, self.footer_start)
|
||||
else:
|
||||
main_rect = QtCore.QRect(theme.font_main_x, theme.font_main_y,
|
||||
theme.font_main_width - 1, theme.font_main_height - 1)
|
||||
if not theme.font_footer_override:
|
||||
footer_rect = QtCore.QRect(10, self.footer_start, self.width - 1,
|
||||
self.height-self.footer_start)
|
||||
footer_rect = QtCore.QRect(10, self.footer_start,
|
||||
self.width - 1, self.height - self.footer_start)
|
||||
else:
|
||||
footer_rect = QtCore.QRect(theme.font_footer_x,
|
||||
theme.font_footer_y, theme.font_footer_width - 1,
|
||||
|
@ -192,10 +167,13 @@ class RenderManager(object):
|
|||
The theme to generated a preview for.
|
||||
"""
|
||||
log.debug(u'generate preview')
|
||||
self.calculate_default(QtCore.QSize(1024, 768))
|
||||
#set the default image size for previews
|
||||
self.calculate_default(self.screens.preview[u'size'])
|
||||
self.renderer.set_theme(themedata)
|
||||
self.build_text_rectangle(themedata)
|
||||
self.renderer.set_frame_dest(self.width, self.height, True)
|
||||
#Reset the real screen size for subsequent render requests
|
||||
self.calculate_default(self.screens.current[u'size'])
|
||||
verse = u'Amazing Grace!\n'\
|
||||
'How sweet the sound\n'\
|
||||
'To save a wretch like me;\n'\
|
||||
|
@ -206,6 +184,7 @@ class RenderManager(object):
|
|||
footer.append(u'Public Domain')
|
||||
footer.append(u'CCLI 123456')
|
||||
formatted = self.renderer.format_slide(verse, False)
|
||||
#Only Render the first slide page returned
|
||||
return self.renderer.generate_frame_from_lines(formatted[0], footer)[u'main']
|
||||
|
||||
def format_slide(self, words):
|
||||
|
@ -234,48 +213,18 @@ class RenderManager(object):
|
|||
self.renderer.set_frame_dest(self.width, self.height)
|
||||
return self.renderer.generate_frame_from_lines(main_text, footer_text)
|
||||
|
||||
def resize_image(self, image, width=0, height=0):
|
||||
"""
|
||||
Resize an image to fit on the current screen.
|
||||
|
||||
``image``
|
||||
The image to resize.
|
||||
"""
|
||||
preview = QtGui.QImage(image)
|
||||
if width == 0:
|
||||
w = self.width
|
||||
h = self.height
|
||||
else:
|
||||
w = width
|
||||
h = height
|
||||
preview = preview.scaled(w, h, QtCore.Qt.KeepAspectRatio,
|
||||
QtCore.Qt.SmoothTransformation)
|
||||
realw = preview.width();
|
||||
realh = preview.height()
|
||||
# and move it to the centre of the preview space
|
||||
newImage = QtGui.QImage(w, h, QtGui.QImage.Format_ARGB32_Premultiplied)
|
||||
newImage.fill(QtCore.Qt.black)
|
||||
painter = QtGui.QPainter(newImage)
|
||||
painter.drawImage((w - realw) / 2, (h - realh) / 2, preview)
|
||||
return newImage
|
||||
|
||||
def calculate_default(self, screen):
|
||||
"""
|
||||
Calculate the default dimentions of the screen.
|
||||
|
||||
``screen``
|
||||
The QWidget instance of the screen.
|
||||
The QSize of the screen.
|
||||
"""
|
||||
log.debug(u'calculate default %s', screen)
|
||||
#size fixed so reflects the preview size.
|
||||
if self.current_display == 0:
|
||||
self.width = 1024
|
||||
self.height = 768
|
||||
else:
|
||||
self.width = screen.width()
|
||||
self.height = screen.height()
|
||||
self.width = screen.width()
|
||||
self.height = screen.height()
|
||||
self.screen_ratio = float(self.height) / float(self.width)
|
||||
log.debug(u'calculate default %d, %d, %f',
|
||||
self.width, self.height, self.screen_ratio )
|
||||
# 90% is start of footer
|
||||
self.footer_start = int(self.height * 0.90)
|
||||
self.footer_start = int(self.height * 0.90)
|
||||
|
|
|
@ -30,7 +30,9 @@ import uuid
|
|||
|
||||
from PyQt4 import QtGui
|
||||
|
||||
from openlp.core.lib import build_icon, Receiver
|
||||
from openlp.core.lib import build_icon, Receiver, resize_image
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
class ServiceItemType(object):
|
||||
"""
|
||||
|
@ -46,8 +48,6 @@ class ServiceItem(object):
|
|||
the service manager, the slide controller, and the projection screen
|
||||
compositor.
|
||||
"""
|
||||
global log
|
||||
log = logging.getLogger(u'ServiceItem')
|
||||
log.info(u'Service Item created')
|
||||
|
||||
def __init__(self, plugin=None):
|
||||
|
@ -72,6 +72,8 @@ class ServiceItem(object):
|
|||
self._raw_frames = []
|
||||
self._display_frames = []
|
||||
self._uuid = unicode(uuid.uuid1())
|
||||
self.autoPreviewAllowed = False
|
||||
self.notes = u''
|
||||
|
||||
def addIcon(self, icon):
|
||||
"""
|
||||
|
@ -102,16 +104,19 @@ class ServiceItem(object):
|
|||
formated = self.RenderManager.format_slide(slide[u'raw_slide'])
|
||||
for format in formated:
|
||||
lines = u''
|
||||
title = u''
|
||||
for line in format:
|
||||
if title == u'':
|
||||
title = line
|
||||
lines += line + u'\n'
|
||||
title = lines.split(u'\n')[0]
|
||||
self._display_frames.append({u'title': title, \
|
||||
u'text': lines, u'verseTag': slide[u'verseTag'] })
|
||||
u'text': lines.rstrip(), u'verseTag': slide[u'verseTag'] })
|
||||
log.log(15, u'Formatting took %4s' % (time.time() - before))
|
||||
elif self.service_item_type == ServiceItemType.Image:
|
||||
for slide in self._raw_frames:
|
||||
slide[u'image'] = \
|
||||
self.RenderManager.resize_image(slide[u'image'])
|
||||
resize_image(slide[u'image'], self.RenderManager.width,
|
||||
self.RenderManager.height)
|
||||
elif self.service_item_type == ServiceItemType.Command:
|
||||
pass
|
||||
else:
|
||||
|
@ -119,7 +124,7 @@ class ServiceItem(object):
|
|||
|
||||
def render_individual(self, row):
|
||||
"""
|
||||
Takes an array of text and geneates an Image from the
|
||||
Takes an array of text and generates an Image from the
|
||||
theme. It assumes the text will fit on the screen as it
|
||||
has generated by the render method above.
|
||||
"""
|
||||
|
@ -129,8 +134,12 @@ class ServiceItem(object):
|
|||
else:
|
||||
self.RenderManager.set_override_theme(self.theme)
|
||||
format = self._display_frames[row][u'text'].split(u'\n')
|
||||
frame = self.RenderManager.generate_slide(format,
|
||||
self.raw_footer)
|
||||
#if screen blank then do not display footer
|
||||
if format[0]:
|
||||
frame = self.RenderManager.generate_slide(format,
|
||||
self.raw_footer)
|
||||
else:
|
||||
frame = self.RenderManager.generate_slide(format,u'')
|
||||
return frame
|
||||
|
||||
def add_from_image(self, path, title, image):
|
||||
|
@ -197,7 +206,9 @@ class ServiceItem(object):
|
|||
u'icon':self.icon,
|
||||
u'footer':self.raw_footer,
|
||||
u'type':self.service_item_type,
|
||||
u'audit':self.audit
|
||||
u'audit':self.audit,
|
||||
u'notes':self.notes,
|
||||
u'preview':self.autoPreviewAllowed
|
||||
}
|
||||
service_data = []
|
||||
if self.service_item_type == ServiceItemType.Text:
|
||||
|
@ -231,6 +242,8 @@ class ServiceItem(object):
|
|||
self.addIcon(header[u'icon'])
|
||||
self.raw_footer = header[u'footer']
|
||||
self.audit = header[u'audit']
|
||||
self.autoPreviewAllowed = header[u'preview']
|
||||
self.notes = header[u'notes']
|
||||
if self.service_item_type == ServiceItemType.Text:
|
||||
for slide in serviceitem[u'serviceitem'][u'data']:
|
||||
self._raw_frames.append(slide)
|
||||
|
@ -309,4 +322,4 @@ class ServiceItem(object):
|
|||
|
||||
def request_audit(self):
|
||||
if self.audit:
|
||||
Receiver.send_message(u'songusage_live', self.audit)
|
||||
Receiver.send_message(u'songusage_live', self.audit)
|
||||
|
|
|
@ -33,7 +33,7 @@ class SettingsManager(object):
|
|||
individual components.
|
||||
"""
|
||||
def __init__(self, screen):
|
||||
self.screen = screen[0]
|
||||
self.screen = screen.current
|
||||
self.width = self.screen[u'size'].width()
|
||||
self.height = self.screen[u'size'].height()
|
||||
self.mainwindow_height = self.height * 0.8
|
||||
|
@ -72,4 +72,4 @@ class SettingsManager(object):
|
|||
u'media manager', isVisible)
|
||||
|
||||
def togglePreviewPanel(self, isVisible):
|
||||
ConfigHelper.set_config(u'user interface', u'preview panel', isVisible)
|
||||
ConfigHelper.set_config(u'user interface', u'preview panel', isVisible)
|
||||
|
|
|
@ -27,6 +27,8 @@ import logging
|
|||
from xml.dom.minidom import Document
|
||||
from xml.etree.ElementTree import ElementTree, XML, dump
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
class SongXMLBuilder(object):
|
||||
"""
|
||||
This class builds the XML used to describe songs.
|
||||
|
@ -42,8 +44,6 @@ class SongXMLBuilder(object):
|
|||
</lyrics>
|
||||
</song>
|
||||
"""
|
||||
global log
|
||||
log = logging.getLogger(u'SongXMLBuilder')
|
||||
log.info(u'SongXMLBuilder Loaded')
|
||||
|
||||
def __init__(self):
|
||||
|
@ -123,8 +123,6 @@ class SongXMLParser(object):
|
|||
</lyrics>
|
||||
</song>
|
||||
"""
|
||||
global log
|
||||
log = logging.getLogger(u'SongXMLParser')
|
||||
log.info(u'SongXMLParser Loaded')
|
||||
|
||||
def __init__(self, xml):
|
||||
|
@ -158,4 +156,4 @@ class SongXMLParser(object):
|
|||
"""
|
||||
Debugging aid to dump XML so that we can see what we have.
|
||||
"""
|
||||
return dump(self.song_xml)
|
||||
return dump(self.song_xml)
|
||||
|
|
|
@ -171,7 +171,8 @@ class ThemeXML(object):
|
|||
self.child_element(background, u'filename', filename)
|
||||
|
||||
def add_font(self, name, color, proportion, override, fonttype=u'main',
|
||||
weight=u'Normal', italics=u'False', indentation=0, xpos=0, ypos=0, width=0, height=0):
|
||||
weight=u'Normal', italics=u'False', indentation=0, xpos=0, ypos=0,
|
||||
width=0, height=0):
|
||||
"""
|
||||
Add a Font.
|
||||
|
||||
|
@ -363,14 +364,14 @@ class ThemeXML(object):
|
|||
master = u''
|
||||
for element in iter:
|
||||
element.text = unicode(element.text).decode('unicode-escape')
|
||||
if len(element.getchildren()) > 0:
|
||||
if element.getchildren():
|
||||
master = element.tag + u'_'
|
||||
else:
|
||||
#background transparent tags have no children so special case
|
||||
if element.tag == u'background':
|
||||
for e in element.attrib.iteritems():
|
||||
setattr(self, element.tag + u'_' + e[0], e[1])
|
||||
if len(element.attrib) > 0:
|
||||
if element.attrib:
|
||||
for e in element.attrib.iteritems():
|
||||
if master == u'font_' and e[0] == u'type':
|
||||
master += e[1] + u'_'
|
||||
|
@ -402,4 +403,4 @@ class ThemeXML(object):
|
|||
for key in dir(self):
|
||||
if key[0:1] != u'_':
|
||||
theme_strings.append(u'%30s: %s' % (key, getattr(self, key)))
|
||||
return u'\n'.join(theme_strings)
|
||||
return u'\n'.join(theme_strings)
|
||||
|
|
|
@ -29,6 +29,8 @@ from PyQt4 import QtCore, QtGui
|
|||
|
||||
from openlp.core.lib import build_icon
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
class OpenLPToolbar(QtGui.QToolBar):
|
||||
"""
|
||||
Lots of toolbars around the place, so it makes sense to have a common way
|
||||
|
@ -43,8 +45,7 @@ class OpenLPToolbar(QtGui.QToolBar):
|
|||
self.icons = {}
|
||||
self.setIconSize(QtCore.QSize(20, 20))
|
||||
self.actions = {}
|
||||
self.log = logging.getLogger(u'OpenLPToolbar')
|
||||
self.log.debug(u'Init done')
|
||||
log.debug(u'Init done')
|
||||
|
||||
def addToolbarButton(self, title, icon, tooltip=None, slot=None,
|
||||
checkable=False):
|
||||
|
@ -119,7 +120,7 @@ class OpenLPToolbar(QtGui.QToolBar):
|
|||
if self.icons[title]:
|
||||
return self.icons[title]
|
||||
else:
|
||||
self.log.error(u'getIconFromTitle - no icon for %s' % title)
|
||||
log.error(u'getIconFromTitle - no icon for %s' % title)
|
||||
return QtGui.QIcon()
|
||||
|
||||
def makeWidgetsInvisible(self, widgets):
|
||||
|
@ -152,4 +153,4 @@ class OpenLPToolbar(QtGui.QToolBar):
|
|||
push_button.setCheckable(True)
|
||||
push_button.setFlat(True)
|
||||
self.addWidget(push_button)
|
||||
return push_button
|
||||
return push_button
|
||||
|
|
|
@ -30,7 +30,7 @@ from PyQt4 import QtGui
|
|||
|
||||
DelphiColors={"clRed":0xFF0000,
|
||||
"clBlue":0x0000FF,
|
||||
"clYellow":0x0FFFF00,
|
||||
"clYellow":0xFFFF00,
|
||||
"clBlack":0x000000,
|
||||
"clWhite":0xFFFFFF}
|
||||
|
||||
|
@ -113,6 +113,7 @@ class Theme(object):
|
|||
root = ElementTree(element=XML(xml))
|
||||
iter = root.getiterator()
|
||||
for element in iter:
|
||||
delphiColorChange = False
|
||||
if element.tag != u'Theme':
|
||||
t = element.text
|
||||
val = 0
|
||||
|
@ -128,6 +129,7 @@ class Theme(object):
|
|||
pass
|
||||
elif DelphiColors.has_key(t):
|
||||
val = DelphiColors[t]
|
||||
delphiColorChange = True
|
||||
else:
|
||||
try:
|
||||
val = int(t)
|
||||
|
@ -136,7 +138,10 @@ class Theme(object):
|
|||
if (element.tag.find(u'Color') > 0 or
|
||||
(element.tag.find(u'BackgroundParameter') == 0 and type(val) == type(0))):
|
||||
# convert to a wx.Colour
|
||||
val = QtGui.QColor((val>>16) & 0xFF, (val>>8)&0xFF, val&0xFF)
|
||||
if not delphiColorChange:
|
||||
val = QtGui.QColor(val&0xFF, (val>>8)&0xFF, (val>>16)&0xFF)
|
||||
else:
|
||||
val = QtGui.QColor((val>>16)&0xFF, (val>>8)&0xFF, val&0xFF)
|
||||
setattr(self, element.tag, val)
|
||||
|
||||
def __str__(self):
|
||||
|
|
|
@ -23,16 +23,15 @@
|
|||
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
||||
###############################################################################
|
||||
|
||||
#from slidecontroller import MasterToolbar
|
||||
from serviceitemform import ServiceItemNoteForm
|
||||
from screen import ScreenList
|
||||
from maindisplay import MainDisplay
|
||||
from amendthemeform import AmendThemeForm
|
||||
from slidecontroller import SlideController
|
||||
from splashscreen import SplashScreen
|
||||
from alertstab import AlertsTab
|
||||
from generaltab import GeneralTab
|
||||
from themestab import ThemesTab
|
||||
from aboutform import AboutForm
|
||||
from alertform import AlertForm
|
||||
from pluginform import PluginForm
|
||||
from settingsform import SettingsForm
|
||||
from mediadockmanager import MediaDockManager
|
||||
|
@ -42,4 +41,4 @@ from mainwindow import MainWindow
|
|||
|
||||
__all__ = ['SplashScreen', 'AboutForm', 'SettingsForm', 'MainWindow',
|
||||
'MainDisplay', 'SlideController', 'ServiceManager', 'ThemeManager',
|
||||
'AmendThemeForm', 'MediaDockManager', 'ThemeLevel']
|
||||
'AmendThemeForm', 'MediaDockManager', 'ServiceItemNoteForm']
|
||||
|
|
|
@ -25,7 +25,6 @@
|
|||
|
||||
from PyQt4 import QtCore, QtGui
|
||||
|
||||
from openlp.core.lib import build_icon
|
||||
from aboutdialog import Ui_AboutDialog
|
||||
|
||||
class AboutForm(QtGui.QDialog, Ui_AboutDialog):
|
||||
|
|
|
@ -1,102 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
|
||||
|
||||
###############################################################################
|
||||
# OpenLP - Open Source Lyrics Projection #
|
||||
# --------------------------------------------------------------------------- #
|
||||
# Copyright (c) 2008-2010 Raoul Snyman #
|
||||
# Portions copyright (c) 2008-2010 Tim Bentley, Jonathan Corwin, Michael #
|
||||
# Gorven, Scott Guerrieri, Maikel Stuivenberg, Martin Thompson, Jon Tibble, #
|
||||
# Carsten Tinggaard #
|
||||
# --------------------------------------------------------------------------- #
|
||||
# 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
|
||||
from PyQt4 import QtCore, QtGui
|
||||
from openlp.core.lib import build_icon
|
||||
|
||||
class AlertForm(QtGui.QDialog):
|
||||
global log
|
||||
log = logging.getLogger(u'AlertForm')
|
||||
|
||||
def __init__(self, parent=None):
|
||||
QtGui.QDialog.__init__(self, parent)
|
||||
self.parent = parent
|
||||
self.setupUi(self)
|
||||
log.debug(u'Defined')
|
||||
|
||||
def setupUi(self, AlertForm):
|
||||
AlertForm.setObjectName(u'AlertForm')
|
||||
AlertForm.resize(370, 110)
|
||||
icon = build_icon(u':/icon/openlp-logo-16x16.png')
|
||||
AlertForm.setWindowIcon(icon)
|
||||
self.AlertFormLayout = QtGui.QVBoxLayout(AlertForm)
|
||||
self.AlertFormLayout.setSpacing(8)
|
||||
self.AlertFormLayout.setMargin(8)
|
||||
self.AlertFormLayout.setObjectName(u'AlertFormLayout')
|
||||
self.AlertEntryWidget = QtGui.QWidget(AlertForm)
|
||||
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Preferred)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(self.AlertEntryWidget.sizePolicy().hasHeightForWidth())
|
||||
self.AlertEntryWidget.setSizePolicy(sizePolicy)
|
||||
self.AlertEntryWidget.setObjectName(u'AlertEntryWidget')
|
||||
self.AlertEntryLabel = QtGui.QLabel(self.AlertEntryWidget)
|
||||
self.AlertEntryLabel.setGeometry(QtCore.QRect(0, 0, 353, 16))
|
||||
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Fixed)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(self.AlertEntryLabel.sizePolicy().hasHeightForWidth())
|
||||
self.AlertEntryLabel.setSizePolicy(sizePolicy)
|
||||
self.AlertEntryLabel.setObjectName(u'AlertEntryLabel')
|
||||
self.AlertEntryEditItem = QtGui.QLineEdit(self.AlertEntryWidget)
|
||||
self.AlertEntryEditItem.setGeometry(QtCore.QRect(0, 20, 353, 26))
|
||||
self.AlertEntryEditItem.setObjectName(u'AlertEntryEditItem')
|
||||
self.AlertFormLayout.addWidget(self.AlertEntryWidget)
|
||||
self.ButtonBoxWidget = QtGui.QWidget(AlertForm)
|
||||
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Preferred)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(self.ButtonBoxWidget.sizePolicy().hasHeightForWidth())
|
||||
self.ButtonBoxWidget.setSizePolicy(sizePolicy)
|
||||
self.ButtonBoxWidget.setObjectName(u'ButtonBoxWidget')
|
||||
self.horizontalLayout = QtGui.QHBoxLayout(self.ButtonBoxWidget)
|
||||
self.horizontalLayout.setSpacing(8)
|
||||
self.horizontalLayout.setMargin(0)
|
||||
self.horizontalLayout.setObjectName(u'horizontalLayout')
|
||||
spacerItem = QtGui.QSpacerItem(267, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
|
||||
self.horizontalLayout.addItem(spacerItem)
|
||||
self.DisplayButton = QtGui.QPushButton(self.ButtonBoxWidget)
|
||||
self.DisplayButton.setObjectName(u'DisplayButton')
|
||||
self.horizontalLayout.addWidget(self.DisplayButton)
|
||||
self.CancelButton = QtGui.QPushButton(self.ButtonBoxWidget)
|
||||
self.CancelButton.setObjectName(u'CancelButton')
|
||||
self.horizontalLayout.addWidget(self.CancelButton)
|
||||
self.AlertFormLayout.addWidget(self.ButtonBoxWidget)
|
||||
|
||||
self.retranslateUi(AlertForm)
|
||||
|
||||
QtCore.QObject.connect(self.CancelButton, QtCore.SIGNAL(u'clicked()'), AlertForm.close)
|
||||
QtCore.QObject.connect(self.DisplayButton, QtCore.SIGNAL(u'clicked()'), self.onDisplayClicked)
|
||||
QtCore.QMetaObject.connectSlotsByName(AlertForm)
|
||||
|
||||
def retranslateUi(self, AlertForm):
|
||||
AlertForm.setWindowTitle(self.trUtf8('Alert Message'))
|
||||
self.AlertEntryLabel.setText(self.trUtf8('Alert Text:'))
|
||||
self.DisplayButton.setText(self.trUtf8('Display'))
|
||||
self.CancelButton.setText(self.trUtf8('Cancel'))
|
||||
|
||||
def onDisplayClicked(self):
|
||||
self.parent.mainDisplay.displayAlert(unicode(self.AlertEntryEditItem.text()))
|
|
@ -694,8 +694,14 @@ class AmendThemeForm(QtGui.QDialog, Ui_AmendThemeDialog):
|
|||
if self.allowPreview:
|
||||
#calculate main number of rows
|
||||
metrics = self._getThemeMetrics()
|
||||
line_height = metrics.height()
|
||||
if self.theme.display_shadow:
|
||||
line_height += int(self.theme.display_shadow_size)
|
||||
if self.theme.display_outline:
|
||||
# pixels top/bottom
|
||||
line_height += 2 * int(self.theme.display_outline_size)
|
||||
page_length = \
|
||||
(self.FontMainHeightSpinBox.value() / metrics.height() - 2) - 1
|
||||
((self.FontMainHeightSpinBox.value()) / line_height )
|
||||
log.debug(u'Page Length area height %s, metrics %s, lines %s' %
|
||||
(self.FontMainHeightSpinBox.value(), metrics.height(),
|
||||
page_length))
|
||||
|
@ -719,4 +725,4 @@ class AmendThemeForm(QtGui.QDialog, Ui_AmendThemeDialog):
|
|||
if self.theme.font_main_width < metrics.maxWidth() * 2 + 64:
|
||||
self.theme.font_main_width = metrics.maxWidth() * 2 + 64
|
||||
self.FontMainWidthSpinBox.setValue(self.theme.font_main_width)
|
||||
return metrics
|
||||
return metrics
|
||||
|
|
|
@ -87,6 +87,10 @@ class GeneralTab(SettingsTab):
|
|||
self.SaveCheckServiceCheckBox.setObjectName(u'SaveCheckServiceCheckBox')
|
||||
self.SettingsLayout.addWidget(self.SaveCheckServiceCheckBox)
|
||||
self.GeneralLeftLayout.addWidget(self.SettingsGroupBox)
|
||||
self.AutoPreviewCheckBox = QtGui.QCheckBox(self.SettingsGroupBox)
|
||||
self.AutoPreviewCheckBox.setObjectName(u'AutoPreviewCheckBox')
|
||||
self.SettingsLayout.addWidget(self.AutoPreviewCheckBox)
|
||||
self.GeneralLeftLayout.addWidget(self.SettingsGroupBox)
|
||||
self.GeneralLeftSpacer = QtGui.QSpacerItem(20, 40,
|
||||
QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding)
|
||||
self.GeneralLeftLayout.addItem(self.GeneralLeftSpacer)
|
||||
|
@ -137,6 +141,8 @@ class GeneralTab(SettingsTab):
|
|||
QtCore.SIGNAL(u'stateChanged(int)'), self.onShowSplashCheckBoxChanged)
|
||||
QtCore.QObject.connect(self.SaveCheckServiceCheckBox,
|
||||
QtCore.SIGNAL(u'stateChanged(int)'), self.onSaveCheckServiceCheckBox)
|
||||
QtCore.QObject.connect(self.AutoPreviewCheckBox,
|
||||
QtCore.SIGNAL(u'stateChanged(int)'), self.onAutoPreviewCheckBox)
|
||||
QtCore.QObject.connect(self.NumberEdit,
|
||||
QtCore.SIGNAL(u'editingFinished()'), self.onNumberEditLostFocus)
|
||||
QtCore.QObject.connect(self.UsernameEdit,
|
||||
|
@ -153,6 +159,7 @@ class GeneralTab(SettingsTab):
|
|||
self.ShowSplashCheckBox.setText(self.trUtf8('Show the splash screen'))
|
||||
self.SettingsGroupBox.setTitle(self.trUtf8('Application Settings'))
|
||||
self.SaveCheckServiceCheckBox.setText(self.trUtf8('Prompt to save Service before starting New'))
|
||||
self.AutoPreviewCheckBox.setText(self.trUtf8('Preview Next Song from Service Manager'))
|
||||
self.CCLIGroupBox.setTitle(self.trUtf8('CCLI Details'))
|
||||
self.NumberLabel.setText(self.trUtf8('CCLI Number:'))
|
||||
self.UsernameLabel.setText(self.trUtf8('SongSelect Username:'))
|
||||
|
@ -173,6 +180,9 @@ class GeneralTab(SettingsTab):
|
|||
def onSaveCheckServiceCheckBox(self, value):
|
||||
self.PromptSaveService = (value == QtCore.Qt.Checked)
|
||||
|
||||
def onAutoPreviewCheckBox(self, value):
|
||||
self.AutoPreview = (value == QtCore.Qt.Checked)
|
||||
|
||||
def onNumberEditLostFocus(self):
|
||||
self.CCLINumber = self.NumberEdit.displayText()
|
||||
|
||||
|
@ -183,7 +193,7 @@ class GeneralTab(SettingsTab):
|
|||
self.Password = self.PasswordEdit.displayText()
|
||||
|
||||
def load(self):
|
||||
for screen in self.screen_list:
|
||||
for screen in self.screen_list.screen_list:
|
||||
screen_name = u'%s %d' % (self.trUtf8('Screen'), screen[u'number'] + 1)
|
||||
if screen[u'primary']:
|
||||
screen_name = u'%s (%s)' % (screen_name, self.trUtf8('primary'))
|
||||
|
@ -194,6 +204,7 @@ class GeneralTab(SettingsTab):
|
|||
self.AutoOpen = str_to_bool(self.config.get_config(u'auto open', u'False'))
|
||||
self.ShowSplash = str_to_bool(self.config.get_config(u'show splash', u'True'))
|
||||
self.PromptSaveService = str_to_bool(self.config.get_config(u'save prompt', u'False'))
|
||||
self.AutoPreview = str_to_bool(self.config.get_config(u'auto preview', u'False'))
|
||||
self.CCLINumber = unicode(self.config.get_config(u'ccli number', u''))
|
||||
self.Username = unicode(self.config.get_config(u'songselect username', u''))
|
||||
self.Password = unicode(self.config.get_config(u'songselect password', u''))
|
||||
|
@ -203,6 +214,7 @@ class GeneralTab(SettingsTab):
|
|||
self.WarningCheckBox.setChecked(self.Warning)
|
||||
self.AutoOpenCheckBox.setChecked(self.AutoOpen)
|
||||
self.ShowSplashCheckBox.setChecked(self.ShowSplash)
|
||||
self.AutoPreviewCheckBox.setChecked(self.AutoPreview)
|
||||
self.NumberEdit.setText(self.CCLINumber)
|
||||
self.UsernameEdit.setText(self.Username)
|
||||
self.PasswordEdit.setText(self.Password)
|
||||
|
@ -213,6 +225,7 @@ class GeneralTab(SettingsTab):
|
|||
self.config.set_config(u'auto open', self.AutoOpen)
|
||||
self.config.set_config(u'show splash', self.ShowSplash)
|
||||
self.config.set_config(u'save prompt', self.PromptSaveService)
|
||||
self.config.set_config(u'auto preview', self.AutoPreview)
|
||||
self.config.set_config(u'ccli number', self.CCLINumber)
|
||||
self.config.set_config(u'songselect username', self.Username)
|
||||
self.config.set_config(u'songselect password', self.Password)
|
||||
self.config.set_config(u'songselect password', self.Password)
|
||||
|
|
|
@ -25,25 +25,29 @@
|
|||
|
||||
import logging
|
||||
import os
|
||||
import time
|
||||
|
||||
from PyQt4 import QtCore, QtGui
|
||||
from PyQt4.phonon import Phonon
|
||||
|
||||
from openlp.core.lib import Receiver
|
||||
from openlp.core.lib import Receiver, resize_image
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
class DisplayWidget(QtGui.QWidget):
|
||||
"""
|
||||
Customised version of QTableWidget which can respond to keyboard
|
||||
events.
|
||||
"""
|
||||
global log
|
||||
log = logging.getLogger(u'MainDisplay')
|
||||
log.info(u'MainDisplay loaded')
|
||||
|
||||
def __init__(self, parent=None, name=None):
|
||||
QtGui.QWidget.__init__(self, parent)
|
||||
self.parent = parent
|
||||
self.hotkey_map = {QtCore.Qt.Key_Return: 'servicemanager_next_item',
|
||||
QtCore.Qt.Key_Space: 'live_slidecontroller_next_noloop',
|
||||
QtCore.Qt.Key_Enter: 'live_slidecontroller_next_noloop',
|
||||
QtCore.Qt.Key_0: 'servicemanager_next_item',
|
||||
QtCore.Qt.Key_Backspace: 'live_slidecontroller_previous_noloop'}
|
||||
|
||||
def keyPressEvent(self, event):
|
||||
if type(event) == QtGui.QKeyEvent:
|
||||
|
@ -60,6 +64,9 @@ class DisplayWidget(QtGui.QWidget):
|
|||
elif event.key() == QtCore.Qt.Key_PageDown:
|
||||
Receiver.send_message(u'live_slidecontroller_last')
|
||||
event.accept()
|
||||
elif event.key() in self.hotkey_map:
|
||||
Receiver.send_message(self.hotkey_map[event.key()])
|
||||
event.accept()
|
||||
elif event.key() == QtCore.Qt.Key_Escape:
|
||||
self.resetDisplay()
|
||||
event.accept()
|
||||
|
@ -71,8 +78,6 @@ class MainDisplay(DisplayWidget):
|
|||
"""
|
||||
This is the form that is used to display things on the projector.
|
||||
"""
|
||||
global log
|
||||
log = logging.getLogger(u'MainDisplay')
|
||||
log.info(u'MainDisplay Loaded')
|
||||
|
||||
def __init__(self, parent, screens):
|
||||
|
@ -90,31 +95,26 @@ class MainDisplay(DisplayWidget):
|
|||
self.parent = parent
|
||||
self.setWindowTitle(u'OpenLP Display')
|
||||
self.screens = screens
|
||||
self.layout = QtGui.QVBoxLayout(self)
|
||||
self.layout.setSpacing(0)
|
||||
self.layout.setMargin(0)
|
||||
self.layout.setObjectName(u'layout')
|
||||
self.mediaObject = Phonon.MediaObject(self)
|
||||
self.video = Phonon.VideoWidget()
|
||||
self.video.setVisible(False)
|
||||
self.audio = Phonon.AudioOutput(Phonon.VideoCategory, self.mediaObject)
|
||||
Phonon.createPath(self.mediaObject, self.video)
|
||||
Phonon.createPath(self.mediaObject, self.audio)
|
||||
self.layout.insertWidget(0, self.video)
|
||||
self.display = QtGui.QLabel(self)
|
||||
self.display.setScaledContents(True)
|
||||
self.layout.insertWidget(0, self.display)
|
||||
self.display_image = QtGui.QLabel(self)
|
||||
self.display_image.setScaledContents(True)
|
||||
self.display_text = QtGui.QLabel(self)
|
||||
self.display_text.setScaledContents(True)
|
||||
self.display_alert = QtGui.QLabel(self)
|
||||
self.display_alert.setScaledContents(True)
|
||||
self.primary = True
|
||||
self.displayBlank = False
|
||||
self.blankFrame = None
|
||||
self.frame = None
|
||||
self.alertactive = False
|
||||
self.timer_id = 0
|
||||
self.firstTime = True
|
||||
self.mediaLoaded = False
|
||||
self.hasTransition = False
|
||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||
QtCore.SIGNAL(u'alert_text'), self.displayAlert)
|
||||
self.mediaBackground = False
|
||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||
QtCore.SIGNAL(u'live_slide_hide'), self.hideDisplay)
|
||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||
|
@ -126,11 +126,10 @@ class MainDisplay(DisplayWidget):
|
|||
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||
QtCore.SIGNAL(u'media_play'), self.onMediaPlay)
|
||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||
QtCore.SIGNAL(u'media_pause'), self.onMediaPaws)
|
||||
QtCore.SIGNAL(u'media_pause'), self.onMediaPause)
|
||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||
QtCore.SIGNAL(u'media_stop'), self.onMediaStop)
|
||||
|
||||
|
||||
def setup(self, screenNumber):
|
||||
"""
|
||||
Sets up the screen on a particular screen.
|
||||
|
@ -138,54 +137,88 @@ class MainDisplay(DisplayWidget):
|
|||
"""
|
||||
log.debug(u'Setup %s for %s ' %(self.screens, screenNumber))
|
||||
self.setVisible(False)
|
||||
screen = self.screens[screenNumber]
|
||||
if screen[u'number'] != screenNumber:
|
||||
# We will most probably never actually hit this bit, but just in
|
||||
# case the index in the list doesn't match the screen number, we
|
||||
# search for it.
|
||||
for scrn in self.screens:
|
||||
if scrn[u'number'] == screenNumber:
|
||||
screen = scrn
|
||||
break
|
||||
self.setGeometry(screen[u'size'])
|
||||
self.screen = self.screens.current
|
||||
#Sort out screen locations and sizes
|
||||
self.setGeometry(self.screen[u'size'])
|
||||
self.display_alert.setGeometry(self.screen[u'size'])
|
||||
self.video.setGeometry(self.screen[u'size'])
|
||||
self.display_image.resize(self.screen[u'size'].width(),
|
||||
self.screen[u'size'].height())
|
||||
self.display_text.resize(self.screen[u'size'].width(),
|
||||
self.screen[u'size'].height())
|
||||
#Build a custom splash screen
|
||||
self.InitialFrame = QtGui.QImage(
|
||||
screen[u'size'].width(), screen[u'size'].height(),
|
||||
self.screen[u'size'].width(),
|
||||
self.screen[u'size'].height(),
|
||||
QtGui.QImage.Format_ARGB32_Premultiplied)
|
||||
splash_image = QtGui.QImage(u':/graphics/openlp-splash-screen.png')
|
||||
painter_image = QtGui.QPainter()
|
||||
painter_image.begin(self.InitialFrame)
|
||||
painter_image.fillRect(self.InitialFrame.rect(), QtCore.Qt.white)
|
||||
painter_image.drawImage(
|
||||
(screen[u'size'].width() - splash_image.width()) / 2,
|
||||
(screen[u'size'].height() - splash_image.height()) / 2,
|
||||
(self.screen[u'size'].width() - splash_image.width()) / 2,
|
||||
(self.screen[u'size'].height() - splash_image.height()) / 2,
|
||||
splash_image)
|
||||
self.frameView(self.InitialFrame)
|
||||
self.display_image.setPixmap(QtGui.QPixmap.fromImage(self.InitialFrame))
|
||||
self.repaint()
|
||||
#Build a Black screen
|
||||
painter = QtGui.QPainter()
|
||||
self.blankFrame = QtGui.QImage(
|
||||
screen[u'size'].width(), screen[u'size'].height(),
|
||||
self.screen[u'size'].width(),
|
||||
self.screen[u'size'].height(),
|
||||
QtGui.QImage.Format_ARGB32_Premultiplied)
|
||||
painter.begin(self.blankFrame)
|
||||
painter.fillRect(self.blankFrame.rect(), QtCore.Qt.black)
|
||||
#TODO make black when testing finished
|
||||
painter.fillRect(self.blankFrame.rect(), QtCore.Qt.red)
|
||||
#build a blank transparent image
|
||||
self.transparent = QtGui.QPixmap(self.screen[u'size'].width(),
|
||||
self.screen[u'size'].height())
|
||||
self.transparent.fill(QtCore.Qt.transparent)
|
||||
self.display_alert.setPixmap(self.transparent)
|
||||
self.frameView(self.transparent)
|
||||
# To display or not to display?
|
||||
if not screen[u'primary']:
|
||||
if not self.screen[u'primary']:
|
||||
self.showFullScreen()
|
||||
self.primary = False
|
||||
else:
|
||||
self.setVisible(False)
|
||||
self.primary = True
|
||||
Receiver.send_message(u'screen_changed')
|
||||
|
||||
def resetDisplay(self):
|
||||
Receiver.send_message(u'stop_display_loop')
|
||||
if self.primary:
|
||||
self.setVisible(False)
|
||||
else:
|
||||
self.showFullScreen()
|
||||
|
||||
def hideDisplay(self):
|
||||
self.mediaLoaded = True
|
||||
self.setVisible(False)
|
||||
|
||||
def showDisplay(self):
|
||||
self.mediaLoaded = False
|
||||
if not self.primary:
|
||||
self.setVisible(True)
|
||||
self.showFullScreen()
|
||||
Receiver.send_message(u'flush_alert')
|
||||
|
||||
def addImageWithText(self, frame):
|
||||
frame = resize_image(frame,
|
||||
self.screen[u'size'].width(),
|
||||
self.screen[u'size'].height() )
|
||||
self.display_image.setPixmap(QtGui.QPixmap.fromImage(frame))
|
||||
|
||||
def setAlertSize(self, top, height):
|
||||
self.display_alert.setGeometry(
|
||||
QtCore.QRect(0, top,
|
||||
self.screen[u'size'].width(), height))
|
||||
|
||||
def addAlertImage(self, frame, blank=False):
|
||||
if blank:
|
||||
self.display_alert.setPixmap(self.transparent)
|
||||
else:
|
||||
self.display_alert.setPixmap(frame)
|
||||
|
||||
def frameView(self, frame, transition=False):
|
||||
"""
|
||||
|
@ -194,87 +227,43 @@ class MainDisplay(DisplayWidget):
|
|||
``frame``
|
||||
Image frame to be rendered
|
||||
"""
|
||||
if self.timer_id != 0 :
|
||||
self.displayAlert()
|
||||
elif not self.displayBlank:
|
||||
if not self.displayBlank:
|
||||
if transition:
|
||||
if self.hasTransition:
|
||||
if self.frame[u'trans'] is not None:
|
||||
self.display.setPixmap(QtGui.QPixmap.fromImage(self.frame[u'trans']))
|
||||
self.repaint()
|
||||
if frame[u'trans'] is not None:
|
||||
self.display.setPixmap(QtGui.QPixmap.fromImage(frame[u'trans']))
|
||||
self.repaint()
|
||||
self.hasTransition = True
|
||||
self.display.setPixmap(QtGui.QPixmap.fromImage(frame[u'main']))
|
||||
if self.frame is not None:
|
||||
self.display_text.setPixmap(QtGui.QPixmap.fromImage(self.frame))
|
||||
self.repaint()
|
||||
self.frame = None
|
||||
if frame[u'trans'] is not None:
|
||||
self.display_text.setPixmap(QtGui.QPixmap.fromImage(frame[u'trans']))
|
||||
self.repaint()
|
||||
self.frame = frame[u'trans']
|
||||
self.display_text.setPixmap(QtGui.QPixmap.fromImage(frame[u'main']))
|
||||
self.display_frame = frame[u'main']
|
||||
self.repaint()
|
||||
else:
|
||||
self.display.setPixmap(QtGui.QPixmap.fromImage(frame))
|
||||
if isinstance(frame, QtGui.QPixmap):
|
||||
self.display_text.setPixmap(frame)
|
||||
else:
|
||||
self.display_text.setPixmap(QtGui.QPixmap.fromImage(frame))
|
||||
self.display_frame = frame
|
||||
if not self.isVisible():
|
||||
self.setVisible(True)
|
||||
self.showFullScreen()
|
||||
self.frame = frame
|
||||
|
||||
def blankDisplay(self, blanked=True):
|
||||
if blanked:
|
||||
self.displayBlank = True
|
||||
self.display.setPixmap(QtGui.QPixmap.fromImage(self.blankFrame))
|
||||
self.display_text.setPixmap(QtGui.QPixmap.fromImage(self.blankFrame))
|
||||
else:
|
||||
self.displayBlank = False
|
||||
if self.frame:
|
||||
self.frameView(self.frame)
|
||||
if blanked != self.parent.LiveController.blankButton.isChecked():
|
||||
self.parent.LiveController.blankButton.setChecked(self.displayBlank)
|
||||
self.parent.generalConfig.set_config(u'screen blank', self.displayBlank)
|
||||
|
||||
def displayAlert(self, text=u''):
|
||||
"""
|
||||
Called from the Alert Tab to display an alert
|
||||
|
||||
``text``
|
||||
display text
|
||||
"""
|
||||
log.debug(u'display alert called %s' % text)
|
||||
alertTab = self.parent.settingsForm.AlertsTab
|
||||
if isinstance(self.frame, QtGui.QImage):
|
||||
alertframe = QtGui.QPixmap.fromImage(self.frame)
|
||||
else:
|
||||
alertframe = QtGui.QPixmap.fromImage(self.frame[u'main'])
|
||||
painter = QtGui.QPainter(alertframe)
|
||||
top = alertframe.rect().height() * 0.9
|
||||
painter.fillRect(
|
||||
QtCore.QRect(
|
||||
0, top, alertframe.rect().width(),
|
||||
alertframe.rect().height() - top),
|
||||
QtGui.QColor(alertTab.bg_color))
|
||||
font = QtGui.QFont()
|
||||
font.setFamily(alertTab.font_face)
|
||||
font.setBold(True)
|
||||
font.setPointSize(40)
|
||||
painter.setFont(font)
|
||||
painter.setPen(QtGui.QColor(alertTab.font_color))
|
||||
x, y = (0, top)
|
||||
metrics = QtGui.QFontMetrics(font)
|
||||
painter.drawText(
|
||||
x, y + metrics.height() - metrics.descent() - 1, text)
|
||||
painter.end()
|
||||
self.display.setPixmap(alertframe)
|
||||
# check to see if we have a timer running
|
||||
if self.timer_id == 0:
|
||||
self.timer_id = self.startTimer(int(alertTab.timeout) * 1000)
|
||||
|
||||
def timerEvent(self, event):
|
||||
if event.timerId() == self.timer_id:
|
||||
if isinstance(self.frame, QtGui.QImage):
|
||||
self.display.setPixmap(QtGui.QPixmap.fromImage(self.frame))
|
||||
else:
|
||||
self.display.setPixmap(QtGui.QPixmap.fromImage(self.frame[u'main']))
|
||||
self.killTimer(self.timer_id)
|
||||
self.timer_id = 0
|
||||
if self.display_frame:
|
||||
self.frameView(self.display_frame)
|
||||
|
||||
def onMediaQueue(self, message):
|
||||
log.debug(u'Queue new media message %s' % message)
|
||||
self.display.close()
|
||||
self.display_image.close()
|
||||
self.display_text.close()
|
||||
self.display_alert.close()
|
||||
file = os.path.join(message[1], message[2])
|
||||
if self.firstTime:
|
||||
self.mediaObject.setCurrentSource(Phonon.MediaSource(file))
|
||||
|
@ -287,29 +276,33 @@ class MainDisplay(DisplayWidget):
|
|||
log.debug(u'Play the new media, Live ')
|
||||
if not self.mediaLoaded and not self.displayBlank:
|
||||
self.blankDisplay()
|
||||
self.display_frame = self.blankFrame
|
||||
self.firstTime = True
|
||||
self.mediaLoaded = True
|
||||
self.display.hide()
|
||||
self.display_image.hide()
|
||||
self.display_text.hide()
|
||||
self.display_alert.hide()
|
||||
self.video.setFullScreen(True)
|
||||
self.video.setVisible(True)
|
||||
self.mediaObject.play()
|
||||
if self.primary:
|
||||
self.setVisible(True)
|
||||
self.setVisible(True)
|
||||
self.hide()
|
||||
|
||||
def onMediaPaws(self):
|
||||
def onMediaPause(self):
|
||||
log.debug(u'Media paused by user')
|
||||
self.mediaObject.pause()
|
||||
|
||||
def onMediaStop(self):
|
||||
log.debug(u'Media stopped by user')
|
||||
self.mediaObject.stop()
|
||||
self.onMediaFinish()
|
||||
|
||||
def onMediaFinish(self):
|
||||
log.debug(u'Reached end of media playlist')
|
||||
if self.primary:
|
||||
self.setVisible(False)
|
||||
self.mediaObject.stop()
|
||||
self.mediaObject.clearQueue()
|
||||
self.mediaLoaded = False
|
||||
self.video.setVisible(False)
|
||||
self.display.show()
|
||||
self.display_text.show()
|
||||
self.display_image.show()
|
||||
self.blankDisplay(False)
|
||||
|
|
|
@ -25,31 +25,55 @@
|
|||
|
||||
import os
|
||||
import logging
|
||||
import time
|
||||
|
||||
from PyQt4 import QtCore, QtGui
|
||||
|
||||
from openlp.core.ui import AboutForm, SettingsForm, AlertForm, \
|
||||
from openlp.core.ui import AboutForm, SettingsForm, \
|
||||
ServiceManager, ThemeManager, MainDisplay, SlideController, \
|
||||
PluginForm, MediaDockManager
|
||||
from openlp.core.lib import RenderManager, PluginConfig, build_icon, \
|
||||
OpenLPDockWidget, SettingsManager, PluginManager, Receiver, str_to_bool
|
||||
from openlp.core.utils import check_latest_version
|
||||
from openlp.core.utils import check_latest_version, AppLocation
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
media_manager_style = """
|
||||
QToolBox::tab {
|
||||
background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
|
||||
stop: 0 palette(midlight), stop: 1.0 palette(mid));
|
||||
stop: 0 palette(button), stop: 1.0 palette(dark));
|
||||
border-width: 1px;
|
||||
border-style: outset;
|
||||
border-color: palette(midlight);
|
||||
border-color: palette(dark);
|
||||
border-radius: 5px;
|
||||
}
|
||||
QToolBox::tab:selected {
|
||||
background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
|
||||
stop: 0 palette(light), stop: 1.0 palette(mid));
|
||||
border-color: palette(light);
|
||||
stop: 0 palette(light), stop: 1.0 palette(button));
|
||||
border-color: palette(button);
|
||||
}
|
||||
"""
|
||||
class VersionThread(QtCore.QThread):
|
||||
"""
|
||||
A special Qt thread class to fetch the version of OpenLP from the website.
|
||||
This is threaded so that it doesn't affect the loading time of OpenLP.
|
||||
"""
|
||||
def __init__(self, parent, app_version, generalConfig):
|
||||
QtCore.QThread.__init__(self, parent)
|
||||
self.parent = parent
|
||||
self.app_version = app_version
|
||||
self.generalConfig = generalConfig
|
||||
|
||||
def run(self):
|
||||
"""
|
||||
Run the thread.
|
||||
"""
|
||||
time.sleep(2)
|
||||
version = check_latest_version(self.generalConfig, self.app_version)
|
||||
#new version has arrived
|
||||
if version != self.app_version:
|
||||
Receiver.send_message(u'version_check', u'%s' % version)
|
||||
|
||||
|
||||
class Ui_MainWindow(object):
|
||||
def setupUi(self, MainWindow):
|
||||
|
@ -218,13 +242,8 @@ class Ui_MainWindow(object):
|
|||
self.settingsmanager.showServiceManager)
|
||||
self.ViewServiceManagerItem.setIcon(ServiceManagerIcon)
|
||||
self.ViewServiceManagerItem.setObjectName(u'ViewServiceManagerItem')
|
||||
self.ToolsAlertItem = QtGui.QAction(MainWindow)
|
||||
AlertIcon = build_icon(u':/tools/tools_alert.png')
|
||||
self.ToolsAlertItem.setIcon(AlertIcon)
|
||||
self.ToolsAlertItem.setObjectName(u'ToolsAlertItem')
|
||||
self.PluginItem = QtGui.QAction(MainWindow)
|
||||
#PluginIcon = build_icon(u':/tools/tools_alert.png')
|
||||
self.PluginItem.setIcon(AlertIcon)
|
||||
#self.PluginItem.setIcon(AlertIcon)
|
||||
self.PluginItem.setObjectName(u'PluginItem')
|
||||
self.HelpDocumentationItem = QtGui.QAction(MainWindow)
|
||||
ContentsIcon = build_icon(u':/system/system_help_contents.png')
|
||||
|
@ -283,7 +302,6 @@ class Ui_MainWindow(object):
|
|||
self.OptionsMenu.addAction(self.OptionsViewMenu.menuAction())
|
||||
self.OptionsMenu.addSeparator()
|
||||
self.OptionsMenu.addAction(self.OptionsSettingsItem)
|
||||
self.ToolsMenu.addAction(self.ToolsAlertItem)
|
||||
self.ToolsMenu.addAction(self.PluginItem)
|
||||
self.ToolsMenu.addSeparator()
|
||||
self.ToolsMenu.addAction(self.ToolsAddToolItem)
|
||||
|
@ -385,9 +403,6 @@ class Ui_MainWindow(object):
|
|||
self.action_Preview_Panel.setStatusTip(
|
||||
self.trUtf8('Toggle the visibility of the Preview Panel'))
|
||||
self.action_Preview_Panel.setShortcut(self.trUtf8('F11'))
|
||||
self.ToolsAlertItem.setText(self.trUtf8('&Alert'))
|
||||
self.ToolsAlertItem.setStatusTip(self.trUtf8('Show an alert message'))
|
||||
self.ToolsAlertItem.setShortcut(self.trUtf8('F7'))
|
||||
self.PluginItem.setText(self.trUtf8('&Plugin List'))
|
||||
self.PluginItem.setStatusTip(self.trUtf8('List the Plugins'))
|
||||
self.PluginItem.setShortcut(self.trUtf8('Alt+F7'))
|
||||
|
@ -415,8 +430,6 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
|
|||
"""
|
||||
The main window.
|
||||
"""
|
||||
global log
|
||||
log = logging.getLogger(u'MainWindow')
|
||||
log.info(u'MainWindow loaded')
|
||||
|
||||
def __init__(self, screens, applicationVersion):
|
||||
|
@ -425,19 +438,16 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
|
|||
plugins.
|
||||
"""
|
||||
QtGui.QMainWindow.__init__(self)
|
||||
self.screenList = screens
|
||||
self.screens = screens
|
||||
self.applicationVersion = applicationVersion
|
||||
self.serviceNotSaved = False
|
||||
self.settingsmanager = SettingsManager(screens)
|
||||
self.generalConfig = PluginConfig(u'General')
|
||||
self.mainDisplay = MainDisplay(self, screens)
|
||||
self.alertForm = AlertForm(self)
|
||||
self.aboutForm = AboutForm(self, applicationVersion)
|
||||
self.settingsForm = SettingsForm(self.screenList, self, self)
|
||||
self.settingsForm = SettingsForm(self.screens, self, self)
|
||||
# Set up the path with plugins
|
||||
pluginpath = os.path.split(os.path.abspath(__file__))[0]
|
||||
pluginpath = os.path.abspath(
|
||||
os.path.join(pluginpath, u'..', u'..', u'plugins'))
|
||||
pluginpath = AppLocation.get_directory(AppLocation.PluginsDir)
|
||||
self.plugin_manager = PluginManager(pluginpath)
|
||||
self.plugin_helpers = {}
|
||||
# Set up the interface
|
||||
|
@ -476,14 +486,14 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
|
|||
self.action_Preview_Panel.setChecked)
|
||||
QtCore.QObject.connect(self.HelpAboutItem,
|
||||
QtCore.SIGNAL(u'triggered()'), self.onHelpAboutItemClicked)
|
||||
QtCore.QObject.connect(self.ToolsAlertItem,
|
||||
QtCore.SIGNAL(u'triggered()'), self.onToolsAlertItemClicked)
|
||||
QtCore.QObject.connect(self.PluginItem,
|
||||
QtCore.SIGNAL(u'triggered()'), self.onPluginItemClicked)
|
||||
QtCore.QObject.connect(self.OptionsSettingsItem,
|
||||
QtCore.SIGNAL(u'triggered()'), self.onOptionsSettingsItemClicked)
|
||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||
QtCore.SIGNAL(u'update_global_theme'), self.defaultThemeChanged)
|
||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||
QtCore.SIGNAL(u'version_check'), self.versionCheck)
|
||||
QtCore.QObject.connect(self.FileNewItem,
|
||||
QtCore.SIGNAL(u'triggered()'),
|
||||
self.ServiceManagerContents.onNewService)
|
||||
|
@ -500,7 +510,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
|
|||
#RenderManager needs to call ThemeManager and
|
||||
#ThemeManager needs to call RenderManager
|
||||
self.RenderManager = RenderManager(self.ThemeManagerContents,
|
||||
self.screenList, self.getMonitorNumber())
|
||||
self.screens, self.getMonitorNumber())
|
||||
#Define the media Dock Manager
|
||||
self.mediaDockManager = MediaDockManager(self.MediaToolBox)
|
||||
log.info(u'Load Plugins')
|
||||
|
@ -511,6 +521,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
|
|||
self.plugin_helpers[u'service'] = self.ServiceManagerContents
|
||||
self.plugin_helpers[u'settings'] = self.settingsForm
|
||||
self.plugin_helpers[u'toolbox'] = self.mediaDockManager
|
||||
self.plugin_helpers[u'maindisplay'] = self.mainDisplay
|
||||
self.plugin_manager.find_plugins(pluginpath, self.plugin_helpers)
|
||||
# hook methods have to happen after find_plugins. Find plugins needs
|
||||
# the controllers hence the hooks have moved from setupUI() to here
|
||||
|
@ -536,20 +547,18 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
|
|||
log.info(u'Load data from Settings')
|
||||
self.settingsForm.postSetUp()
|
||||
|
||||
def versionCheck(self):
|
||||
def versionCheck(self, version):
|
||||
"""
|
||||
Checks the version of the Application called from openlp.pyw
|
||||
"""
|
||||
app_version = self.applicationVersion[u'full']
|
||||
version = check_latest_version(self.generalConfig, app_version)
|
||||
if app_version != version:
|
||||
version_text = unicode(self.trUtf8('OpenLP version %s has been updated '
|
||||
'to version %s\n\nYou can obtain the latest version from http://openlp.org'))
|
||||
QtGui.QMessageBox.question(None,
|
||||
self.trUtf8('OpenLP Version Updated'),
|
||||
version_text % (app_version, version),
|
||||
QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Ok),
|
||||
QtGui.QMessageBox.Ok)
|
||||
version_text = unicode(self.trUtf8('OpenLP version %s has been updated '
|
||||
'to version %s\n\nYou can obtain the latest version from http://openlp.org'))
|
||||
QtGui.QMessageBox.question(self,
|
||||
self.trUtf8('OpenLP Version Updated'),
|
||||
version_text % (app_version, version),
|
||||
QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Ok),
|
||||
QtGui.QMessageBox.Ok)
|
||||
|
||||
def getMonitorNumber(self):
|
||||
"""
|
||||
|
@ -558,11 +567,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
|
|||
monitor number does not exist.
|
||||
"""
|
||||
screen_number = int(self.generalConfig.get_config(u'monitor', 0))
|
||||
monitor_exists = False
|
||||
for screen in self.screenList:
|
||||
if screen[u'number'] == screen_number:
|
||||
monitor_exists = True
|
||||
if not monitor_exists:
|
||||
if not self.screens.screen_exists(screen_number):
|
||||
screen_number = 0
|
||||
return screen_number
|
||||
|
||||
|
@ -580,12 +585,17 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
|
|||
self.ServiceManagerContents.onLoadService(True)
|
||||
if str_to_bool(self.generalConfig.get_config(u'screen blank', False)) \
|
||||
and str_to_bool(self.generalConfig.get_config(u'blank warning', False)):
|
||||
QtGui.QMessageBox.question(None,
|
||||
self.LiveController.onBlankDisplay(True)
|
||||
QtGui.QMessageBox.question(self,
|
||||
self.trUtf8('OpenLP Main Display Blanked'),
|
||||
self.trUtf8('The Main Display has been blanked out'),
|
||||
QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Ok),
|
||||
QtGui.QMessageBox.Ok)
|
||||
self.LiveController.blankButton.setChecked(True)
|
||||
|
||||
def versionThread(self):
|
||||
app_version = self.applicationVersion[u'full']
|
||||
vT = VersionThread(self, app_version, self.generalConfig)
|
||||
vT.start()
|
||||
|
||||
def onHelpAboutItemClicked(self):
|
||||
"""
|
||||
|
@ -594,12 +604,6 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
|
|||
self.aboutForm.applicationVersion = self.applicationVersion
|
||||
self.aboutForm.exec_()
|
||||
|
||||
def onToolsAlertItemClicked(self):
|
||||
"""
|
||||
Show the Alert form
|
||||
"""
|
||||
self.alertForm.exec_()
|
||||
|
||||
def onPluginItemClicked(self):
|
||||
"""
|
||||
Show the Plugin form
|
||||
|
@ -613,7 +617,8 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
|
|||
"""
|
||||
self.settingsForm.exec_()
|
||||
updated_display = self.getMonitorNumber()
|
||||
if updated_display != self.RenderManager.current_display:
|
||||
if updated_display != self.screens.current_display:
|
||||
self.screens.set_current_display(updated_display)
|
||||
self.RenderManager.update_display(updated_display)
|
||||
self.mainDisplay.setup(updated_display)
|
||||
self.activateWindow()
|
||||
|
@ -623,7 +628,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
|
|||
Hook to close the main window and display windows on exit
|
||||
"""
|
||||
if self.serviceNotSaved:
|
||||
ret = QtGui.QMessageBox.question(None,
|
||||
ret = QtGui.QMessageBox.question(self,
|
||||
self.trUtf8('Save Changes to Service?'),
|
||||
self.trUtf8('Your service has changed, do you want to save those changes?'),
|
||||
QtGui.QMessageBox.StandardButtons(
|
||||
|
@ -704,4 +709,4 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
|
|||
def togglePreviewPanel(self):
|
||||
previewBool = self.PreviewController.Panel.isVisible()
|
||||
self.PreviewController.Panel.setVisible(not previewBool)
|
||||
self.settingsmanager.togglePreviewPanel(not previewBool)
|
||||
self.settingsmanager.togglePreviewPanel(not previewBool)
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
|
||||
import logging
|
||||
|
||||
log = logging.getLogger(u'MediaDockManager')
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
class MediaDockManager(object):
|
||||
|
||||
|
@ -58,4 +58,4 @@ class MediaDockManager(object):
|
|||
if self.media_dock.widget(dock_index):
|
||||
if self.media_dock.widget(dock_index).ConfigSection == name:
|
||||
self.media_dock.widget(dock_index).hide()
|
||||
self.media_dock.removeItem(dock_index)
|
||||
self.media_dock.removeItem(dock_index)
|
||||
|
|
|
@ -30,9 +30,9 @@ from PyQt4 import QtCore, QtGui
|
|||
from openlp.core.lib.plugin import PluginStatus
|
||||
from plugindialog import Ui_PluginViewDialog
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
class PluginForm(QtGui.QDialog, Ui_PluginViewDialog):
|
||||
global log
|
||||
log = logging.getLogger(u'PluginForm')
|
||||
|
||||
def __init__(self, parent=None):
|
||||
QtGui.QDialog.__init__(self, parent)
|
||||
|
@ -126,4 +126,4 @@ class PluginForm(QtGui.QDialog, Ui_PluginViewDialog):
|
|||
elif self.activePlugin.status == PluginStatus.Disabled:
|
||||
status_text = 'Disabled'
|
||||
self.PluginListWidget.currentItem().setText(
|
||||
u'%s (%s)' % (self.activePlugin.name, status_text))
|
||||
u'%s (%s)' % (self.activePlugin.name, status_text))
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
|
||||
|
||||
###############################################################################
|
||||
# OpenLP - Open Source Lyrics Projection #
|
||||
# --------------------------------------------------------------------------- #
|
||||
# Copyright (c) 2008-2010 Raoul Snyman #
|
||||
# Portions copyright (c) 2008-2010 Tim Bentley, Jonathan Corwin, Michael #
|
||||
# Gorven, Scott Guerrieri, Maikel Stuivenberg, Martin Thompson, Jon Tibble, #
|
||||
# Carsten Tinggaard #
|
||||
# --------------------------------------------------------------------------- #
|
||||
# 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
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
class ScreenList(object):
|
||||
"""
|
||||
Wrapper to handle the parameters of the display screen
|
||||
"""
|
||||
log.info(u'Screen loaded')
|
||||
|
||||
def __init__(self):
|
||||
self.preview = None
|
||||
self.current = None
|
||||
self.screen_list = []
|
||||
self.count = 0
|
||||
self.current_display = 0
|
||||
|
||||
def add_screen(self, screen):
|
||||
if screen[u'primary']:
|
||||
self.current = screen
|
||||
self.screen_list.append(screen)
|
||||
self.count += 1
|
||||
|
||||
def screen_exists(self, number):
|
||||
for screen in self.screen_list:
|
||||
if screen[u'number'] == number:
|
||||
return True
|
||||
return False
|
||||
|
||||
def set_current_display(self, number):
|
||||
if number + 1 > self.count:
|
||||
self.current = self.screen_list[0]
|
||||
self.current_display = 0
|
||||
else:
|
||||
self.current = self.screen_list[number]
|
||||
self.preview = self.current
|
||||
self.current_display = number
|
||||
if self.count == 1:
|
||||
self.preview = self.screen_list[0]
|
||||
|
||||
# if self.screen[u'number'] != screenNumber:
|
||||
# # We will most probably never actually hit this bit, but just in
|
||||
# # case the index in the list doesn't match the screen number, we
|
||||
# # search for it.
|
||||
# for scrn in self.screens:
|
||||
# if scrn[u'number'] == screenNumber:
|
||||
# self.screen = scrn
|
||||
# break
|
|
@ -0,0 +1,49 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
|
||||
|
||||
###############################################################################
|
||||
# OpenLP - Open Source Lyrics Projection #
|
||||
# --------------------------------------------------------------------------- #
|
||||
# Copyright (c) 2008-2010 Raoul Snyman #
|
||||
# Portions copyright (c) 2008-2010 Tim Bentley, Jonathan Corwin, Michael #
|
||||
# Gorven, Scott Guerrieri, Maikel Stuivenberg, Martin Thompson, Jon Tibble, #
|
||||
# Carsten Tinggaard #
|
||||
# --------------------------------------------------------------------------- #
|
||||
# This program is free software; you can redistribute it and/or modify it #
|
||||
# under the terms of the GNU General Public License as published by the Free #
|
||||
# Software Foundation; version 2 of the License. #
|
||||
# #
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT #
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
|
||||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
|
||||
# more details. #
|
||||
# #
|
||||
# You should have received a copy of the GNU General Public License along #
|
||||
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
|
||||
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
||||
###############################################################################
|
||||
|
||||
from PyQt4 import QtCore, QtGui
|
||||
|
||||
class Ui_ServiceNoteEdit(object):
|
||||
def setupUi(self, ServiceNoteEdit):
|
||||
ServiceNoteEdit.setObjectName(u'ServiceNoteEdit')
|
||||
ServiceNoteEdit.resize(400, 243)
|
||||
self.widget = QtGui.QWidget(ServiceNoteEdit)
|
||||
self.widget.setGeometry(QtCore.QRect(20, 10, 361, 223))
|
||||
self.widget.setObjectName(u'widget')
|
||||
self.verticalLayout = QtGui.QVBoxLayout(self.widget)
|
||||
self.verticalLayout.setObjectName(u'verticalLayout')
|
||||
self.textEdit = QtGui.QTextEdit(self.widget)
|
||||
self.textEdit.setObjectName(u'textEdit')
|
||||
self.verticalLayout.addWidget(self.textEdit)
|
||||
self.buttonBox = QtGui.QDialogButtonBox(self.widget)
|
||||
self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Cancel|QtGui.QDialogButtonBox.Save)
|
||||
self.buttonBox.setObjectName(u'buttonBox')
|
||||
self.verticalLayout.addWidget(self.buttonBox)
|
||||
|
||||
self.retranslateUi(ServiceNoteEdit)
|
||||
QtCore.QMetaObject.connectSlotsByName(ServiceNoteEdit)
|
||||
|
||||
def retranslateUi(self, ServiceNoteEdit):
|
||||
ServiceNoteEdit.setWindowTitle(self.trUtf8('Service Item Notes'))
|
|
@ -0,0 +1,44 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
|
||||
|
||||
###############################################################################
|
||||
# OpenLP - Open Source Lyrics Projection #
|
||||
# --------------------------------------------------------------------------- #
|
||||
# Copyright (c) 2008-2010 Raoul Snyman #
|
||||
# Portions copyright (c) 2008-2010 Tim Bentley, Jonathan Corwin, Michael #
|
||||
# Gorven, Scott Guerrieri, Maikel Stuivenberg, Martin Thompson, Jon Tibble, #
|
||||
# Carsten Tinggaard #
|
||||
# --------------------------------------------------------------------------- #
|
||||
# This program is free software; you can redistribute it and/or modify it #
|
||||
# under the terms of the GNU General Public License as published by the Free #
|
||||
# Software Foundation; version 2 of the License. #
|
||||
# #
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT #
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
|
||||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
|
||||
# more details. #
|
||||
# #
|
||||
# You should have received a copy of the GNU General Public License along #
|
||||
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
|
||||
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
||||
###############################################################################
|
||||
|
||||
from PyQt4 import QtCore, QtGui
|
||||
from serviceitemdialog import Ui_ServiceNoteEdit
|
||||
|
||||
class ServiceItemNoteForm(QtGui.QDialog, Ui_ServiceNoteEdit):
|
||||
"""
|
||||
This is the form that is used to edit the verses of the song.
|
||||
"""
|
||||
def __init__(self, parent=None):
|
||||
"""
|
||||
Constructor
|
||||
"""
|
||||
QtGui.QDialog.__init__(self, parent)
|
||||
self.setupUi(self)
|
||||
QtCore.QObject.connect(self.buttonBox,
|
||||
QtCore.SIGNAL(u'accepted()'),
|
||||
self.accept)
|
||||
QtCore.QObject.connect(self.buttonBox,
|
||||
QtCore.SIGNAL(u'rejected()'),
|
||||
self.reject)
|
|
@ -28,10 +28,13 @@ import logging
|
|||
import cPickle
|
||||
import zipfile
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
from PyQt4 import QtCore, QtGui
|
||||
|
||||
from openlp.core.lib import PluginConfig, OpenLPToolbar, ServiceItem, \
|
||||
ServiceItemType, contextMenuAction, contextMenuSeparator, contextMenu, \
|
||||
Receiver, contextMenu, str_to_bool
|
||||
contextMenuAction, Receiver, str_to_bool, build_icon
|
||||
from openlp.core.ui import ServiceItemNoteForm
|
||||
|
||||
class ServiceManagerList(QtGui.QTreeWidget):
|
||||
|
||||
|
@ -39,23 +42,6 @@ class ServiceManagerList(QtGui.QTreeWidget):
|
|||
QtGui.QTreeWidget.__init__(self,parent)
|
||||
self.parent = parent
|
||||
|
||||
# def mousePressEvent(self, event):
|
||||
# if event.button() == QtCore.Qt.RightButton:
|
||||
# item = self.itemAt(event.pos())
|
||||
# parentitem = item.parent()
|
||||
# if parentitem is None:
|
||||
# pos = item.data(0, QtCore.Qt.UserRole).toInt()[0]
|
||||
# else:
|
||||
# pos = parentitem.data(0, QtCore.Qt.UserRole).toInt()[0]
|
||||
# serviceItem = self.parent.serviceItems[pos - 1]
|
||||
# if serviceItem[u'data'].edit_enabled:
|
||||
# self.parent.editAction.setVisible(True)
|
||||
# else:
|
||||
# self.parent.editAction.setVisible(False)
|
||||
# event.accept()
|
||||
# else:
|
||||
# event.ignore()
|
||||
|
||||
def keyPressEvent(self, event):
|
||||
if type(event) == QtGui.QKeyEvent:
|
||||
#here accept the event and do something
|
||||
|
@ -91,6 +77,7 @@ class ServiceManagerList(QtGui.QTreeWidget):
|
|||
just tell it what plugin to call
|
||||
"""
|
||||
if event.buttons() != QtCore.Qt.LeftButton:
|
||||
event.ignore()
|
||||
return
|
||||
drag = QtGui.QDrag(self)
|
||||
mimeData = QtCore.QMimeData()
|
||||
|
@ -105,9 +92,6 @@ class ServiceManager(QtGui.QWidget):
|
|||
the resources used into one OSZ file for use on any OpenLP v2 installation.
|
||||
Also handles the UI tasks of moving things up and down etc.
|
||||
"""
|
||||
global log
|
||||
log = logging.getLogger(u'ServiceManager')
|
||||
|
||||
def __init__(self, parent):
|
||||
"""
|
||||
Sets up the service manager, toolbars, list view, et al.
|
||||
|
@ -121,6 +105,7 @@ class ServiceManager(QtGui.QWidget):
|
|||
#Indicates if remoteTriggering is active. If it is the next addServiceItem call
|
||||
#will replace the currently selected one.
|
||||
self.remoteEditTriggered = False
|
||||
self.serviceItemNoteForm = ServiceItemNoteForm()
|
||||
#start with the layout
|
||||
self.Layout = QtGui.QVBoxLayout(self)
|
||||
self.Layout.setSpacing(0)
|
||||
|
@ -161,62 +146,38 @@ class ServiceManager(QtGui.QWidget):
|
|||
self.ServiceManagerList.setAlternatingRowColors(True)
|
||||
self.ServiceManagerList.setHeaderHidden(True)
|
||||
self.ServiceManagerList.setExpandsOnDoubleClick(False)
|
||||
self.ServiceManagerList.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
|
||||
self.ServiceManagerList.customContextMenuRequested.connect(self.contextMenu)
|
||||
self.ServiceManagerList.setObjectName(u'ServiceManagerList')
|
||||
# enable drop
|
||||
self.ServiceManagerList.__class__.dragEnterEvent = self.dragEnterEvent
|
||||
self.ServiceManagerList.__class__.dragMoveEvent = self.dragEnterEvent
|
||||
self.ServiceManagerList.__class__.dropEvent = self.dropEvent
|
||||
# Add a context menu to the service manager list
|
||||
self.ServiceManagerList.setContextMenuPolicy(
|
||||
QtCore.Qt.ActionsContextMenu)
|
||||
self.editAction = contextMenuAction(
|
||||
self.ServiceManagerList, ':/system/system_live.png',
|
||||
self.trUtf8('&Edit Item'), self.remoteEdit)
|
||||
self.ServiceManagerList.addAction(self.editAction)
|
||||
self.ServiceManagerList.addAction(contextMenuSeparator(
|
||||
self.ServiceManagerList))
|
||||
self.ServiceManagerList.addAction(contextMenuAction(
|
||||
self.ServiceManagerList, ':/system/system_preview.png',
|
||||
self.trUtf8('&Preview Verse'), self.makePreview))
|
||||
self.ServiceManagerList.addAction(contextMenuAction(
|
||||
self.ServiceManagerList, ':/system/system_live.png',
|
||||
self.trUtf8('&Show Live'), self.makeLive))
|
||||
self.ServiceManagerList.addAction(contextMenuSeparator(
|
||||
self.ServiceManagerList))
|
||||
self.ServiceManagerList.addAction(contextMenuAction(
|
||||
self.ServiceManagerList, ':/services/service_delete',
|
||||
self.trUtf8('&Remove from Service'), self.onDeleteFromService))
|
||||
self.ServiceManagerList.addAction(contextMenuSeparator(
|
||||
self.ServiceManagerList))
|
||||
self.ThemeMenu = contextMenu(
|
||||
self.ServiceManagerList, '',
|
||||
self.trUtf8('&Change Item Theme'))
|
||||
self.ServiceManagerList.addAction(self.ThemeMenu.menuAction())
|
||||
self.Layout.addWidget(self.ServiceManagerList)
|
||||
# Add the bottom toolbar
|
||||
self.OrderToolbar = OpenLPToolbar(self)
|
||||
self.OrderToolbar.addToolbarButton(
|
||||
self.trUtf8('Move to top'), u':/services/service_top.png',
|
||||
self.trUtf8('Move to &top'), u':/services/service_top.png',
|
||||
self.trUtf8('Move to top'), self.onServiceTop)
|
||||
self.OrderToolbar.addToolbarButton(
|
||||
self.trUtf8('Move up'), u':/services/service_up.png',
|
||||
self.trUtf8('Move &up'), u':/services/service_up.png',
|
||||
self.trUtf8('Move up order'), self.onServiceUp)
|
||||
self.OrderToolbar.addToolbarButton(
|
||||
self.trUtf8('Move down'), u':/services/service_down.png',
|
||||
self.trUtf8('Move &down'), u':/services/service_down.png',
|
||||
self.trUtf8('Move down order'), self.onServiceDown)
|
||||
self.OrderToolbar.addToolbarButton(
|
||||
self.trUtf8('Move to bottom'), u':/services/service_bottom.png',
|
||||
self.trUtf8('Move to &bottom'), u':/services/service_bottom.png',
|
||||
self.trUtf8('Move to end'), self.onServiceEnd)
|
||||
self.OrderToolbar.addSeparator()
|
||||
self.OrderToolbar.addToolbarButton(
|
||||
self.trUtf8('Delete From Service'), u':/services/service_delete.png',
|
||||
self.trUtf8('&Delete From Service'), u':/services/service_delete.png',
|
||||
self.trUtf8('Delete From Service'), self.onDeleteFromService)
|
||||
self.Layout.addWidget(self.OrderToolbar)
|
||||
# Connect up our signals and slots
|
||||
QtCore.QObject.connect(self.ThemeComboBox,
|
||||
QtCore.SIGNAL(u'activated(int)'), self.onThemeComboBoxSelected)
|
||||
QtCore.QObject.connect(self.ServiceManagerList,
|
||||
QtCore.SIGNAL(u'doubleClicked(QModelIndex)'), self.makeLive)
|
||||
QtCore.SIGNAL(u'doubleClicked(QModelIndex)'), self.makeLive)
|
||||
QtCore.QObject.connect(self.ServiceManagerList,
|
||||
QtCore.SIGNAL(u'itemCollapsed(QTreeWidgetItem*)'), self.collapsed)
|
||||
QtCore.QObject.connect(self.ServiceManagerList,
|
||||
|
@ -225,18 +186,99 @@ class ServiceManager(QtGui.QWidget):
|
|||
QtCore.SIGNAL(u'update_themes'), self.updateThemeList)
|
||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||
QtCore.SIGNAL(u'remote_edit_clear'), self.onRemoteEditClear)
|
||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||
QtCore.SIGNAL(u'presentation types'), self.onPresentationTypes)
|
||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||
QtCore.SIGNAL(u'servicemanager_next_item'), self.nextItem)
|
||||
# Last little bits of setting up
|
||||
self.config = PluginConfig(u'ServiceManager')
|
||||
self.servicePath = self.config.get_data_path()
|
||||
self.service_theme = unicode(
|
||||
self.config.get_config(u'service theme', u''))
|
||||
#build the context menu
|
||||
self.menu = QtGui.QMenu()
|
||||
self.editAction = self.menu.addAction(self.trUtf8('&Edit Item'))
|
||||
self.editAction.setIcon(build_icon(u':/services/service_edit.png'))
|
||||
self.notesAction = self.menu.addAction(self.trUtf8('&Notes'))
|
||||
self.notesAction.setIcon(build_icon(u':/services/service_notes.png'))
|
||||
self.deleteAction = self.menu.addAction(self.trUtf8('&Delete From Service'))
|
||||
self.deleteAction.setIcon(build_icon(u':/services/service_delete.png'))
|
||||
self.sep1 = self.menu.addAction(u'')
|
||||
self.sep1.setSeparator(True)
|
||||
self.previewAction = self.menu.addAction(self.trUtf8('&Preview Verse'))
|
||||
self.previewAction.setIcon(build_icon(u':/system/system_preview.png'))
|
||||
self.liveAction = self.menu.addAction(self.trUtf8('&Live Verse'))
|
||||
self.liveAction.setIcon(build_icon(u':/system/system_live.png'))
|
||||
self.sep2 = self.menu.addAction(u'')
|
||||
self.sep2.setSeparator(True)
|
||||
self.themeMenu = QtGui.QMenu(self.trUtf8(u'&Change Item Theme'))
|
||||
self.menu.addMenu(self.themeMenu)
|
||||
|
||||
def contextMenu(self, point):
|
||||
item = self.ServiceManagerList.itemAt(point)
|
||||
if item.parent() is None:
|
||||
pos = item.data(0, QtCore.Qt.UserRole).toInt()[0]
|
||||
else:
|
||||
pos = item.parent().data(0, QtCore.Qt.UserRole).toInt()[0]
|
||||
serviceItem = self.serviceItems[pos - 1]
|
||||
self.editAction.setVisible(False)
|
||||
self.notesAction.setVisible(False)
|
||||
if serviceItem[u'service_item'].edit_enabled:
|
||||
self.editAction.setVisible(True)
|
||||
if item.parent() is None:
|
||||
self.notesAction.setVisible(True)
|
||||
self.themeMenu.menuAction().setVisible(False)
|
||||
if serviceItem[u'service_item'].is_text():
|
||||
self.themeMenu.menuAction().setVisible(True)
|
||||
action = self.menu.exec_(self.ServiceManagerList.mapToGlobal(point))
|
||||
if action == self.editAction:
|
||||
self.remoteEdit()
|
||||
if action == self.deleteAction:
|
||||
self.onDeleteFromService()
|
||||
if action == self.notesAction:
|
||||
self.onServiceItemNoteForm()
|
||||
if action == self.previewAction:
|
||||
self.makePreview()
|
||||
if action == self.liveAction:
|
||||
self.makeLive()
|
||||
|
||||
def onPresentationTypes(self, presentation_types):
|
||||
self.presentation_types = presentation_types
|
||||
|
||||
def onServiceItemNoteForm(self):
|
||||
item, count = self.findServiceItem()
|
||||
self.serviceItemNoteForm.textEdit.setPlainText(
|
||||
self.serviceItems[item][u'service_item'].notes)
|
||||
if self.serviceItemNoteForm.exec_():
|
||||
self.serviceItems[item][u'service_item'].notes = \
|
||||
self.serviceItemNoteForm.textEdit.toPlainText()
|
||||
self.repaintServiceList(item, 0)
|
||||
|
||||
def nextItem(self):
|
||||
"""
|
||||
Called by the SlideController to select the
|
||||
next service item
|
||||
"""
|
||||
if len(self.ServiceManagerList.selectedItems()) == 0:
|
||||
return
|
||||
selected = self.ServiceManagerList.selectedItems()[0]
|
||||
lookFor = 0
|
||||
serviceIterator = QtGui.QTreeWidgetItemIterator(self.ServiceManagerList)
|
||||
while serviceIterator.value():
|
||||
if lookFor == 1 and serviceIterator.value().parent() is None:
|
||||
self.ServiceManagerList.setCurrentItem(serviceIterator.value())
|
||||
self.makeLive()
|
||||
return
|
||||
if serviceIterator.value() == selected:
|
||||
lookFor = 1
|
||||
serviceIterator += 1
|
||||
|
||||
def onMoveSelectionUp(self):
|
||||
"""
|
||||
Moves the selection up the window
|
||||
Called by the up arrow
|
||||
"""
|
||||
serviceIterator = QTreeWidgetItemIterator(self.ServiceManagerList)
|
||||
serviceIterator = QtGui.QTreeWidgetItemIterator(self.ServiceManagerList)
|
||||
tempItem = None
|
||||
setLastItem = False
|
||||
while serviceIterator:
|
||||
|
@ -261,7 +303,7 @@ class ServiceManager(QtGui.QWidget):
|
|||
Moves the selection down the window
|
||||
Called by the down arrow
|
||||
"""
|
||||
serviceIterator = QTreeWidgetItemIterator(self.ServiceManagerList)
|
||||
serviceIterator = QtGui.QTreeWidgetItemIterator(self.ServiceManagerList)
|
||||
firstItem = serviceIterator
|
||||
setSelected = False
|
||||
while serviceIterator:
|
||||
|
@ -348,7 +390,7 @@ class ServiceManager(QtGui.QWidget):
|
|||
if self.parent.serviceNotSaved and \
|
||||
str_to_bool(PluginConfig(u'General').
|
||||
get_config(u'save prompt', u'False')):
|
||||
ret = QtGui.QMessageBox.question(None,
|
||||
ret = QtGui.QMessageBox.question(self,
|
||||
self.trUtf8('Save Changes to Service?'),
|
||||
self.trUtf8('Your service is unsaved, do you want to save those '
|
||||
'changes before creating a new one ?'),
|
||||
|
@ -390,19 +432,35 @@ class ServiceManager(QtGui.QWidget):
|
|||
for itemcount, item in enumerate(self.serviceItems):
|
||||
serviceitem = item[u'service_item']
|
||||
treewidgetitem = QtGui.QTreeWidgetItem(self.ServiceManagerList)
|
||||
treewidgetitem.setText(0,serviceitem.title)
|
||||
treewidgetitem.setIcon(0,serviceitem.iconic_representation)
|
||||
if serviceitem.notes:
|
||||
icon = QtGui.QImage(serviceitem.icon)
|
||||
icon = icon.scaled(80, 80, QtCore.Qt.KeepAspectRatio,
|
||||
QtCore.Qt.SmoothTransformation)
|
||||
overlay = QtGui.QImage(':/services/service_item_notes.png')
|
||||
overlay = overlay.scaled(80, 80, QtCore.Qt.KeepAspectRatio,
|
||||
QtCore.Qt.SmoothTransformation)
|
||||
painter = QtGui.QPainter(icon)
|
||||
painter.drawImage(0, 0, overlay)
|
||||
painter.end()
|
||||
treewidgetitem.setIcon(0, build_icon(icon))
|
||||
else:
|
||||
treewidgetitem.setIcon(0, serviceitem.iconic_representation)
|
||||
treewidgetitem.setText(0, serviceitem.title)
|
||||
treewidgetitem.setToolTip(0, serviceitem.notes)
|
||||
treewidgetitem.setData(0, QtCore.Qt.UserRole,
|
||||
QtCore.QVariant(item[u'order']))
|
||||
treewidgetitem.setExpanded(item[u'expanded'])
|
||||
for count, frame in enumerate(serviceitem.get_frames()):
|
||||
treewidgetitem1 = QtGui.QTreeWidgetItem(treewidgetitem)
|
||||
text = frame[u'title']
|
||||
treewidgetitem1.setText(0,text[:40])
|
||||
treewidgetitem1.setText(0, text[:40])
|
||||
treewidgetitem1.setData(0, QtCore.Qt.UserRole,
|
||||
QtCore.QVariant(count))
|
||||
if serviceItem == itemcount and serviceItemCount == count:
|
||||
self.ServiceManagerList.setCurrentItem(treewidgetitem1)
|
||||
#preserve expanding status as setCurrentItem sets it to True
|
||||
temp = item[u'expanded']
|
||||
self.ServiceManagerList.setCurrentItem(treewidgetitem1)
|
||||
item[u'expanded'] = temp
|
||||
treewidgetitem.setExpanded(item[u'expanded'])
|
||||
|
||||
def onSaveService(self, quick=False):
|
||||
"""
|
||||
|
@ -433,10 +491,10 @@ class ServiceManager(QtGui.QWidget):
|
|||
for item in self.serviceItems:
|
||||
service.append({u'serviceitem':item[u'service_item'].get_service_repr()})
|
||||
if item[u'service_item'].uses_file():
|
||||
for frame in item[u'service_item'].get_frames:
|
||||
for frame in item[u'service_item'].get_frames():
|
||||
path_from = unicode(os.path.join(
|
||||
item[u'service_item'].service_item_path,
|
||||
frame.get_frame_title()))
|
||||
frame[u'title']))
|
||||
zip.write(path_from)
|
||||
file = open(servicefile, u'wb')
|
||||
cPickle.dump(service, file)
|
||||
|
@ -499,7 +557,8 @@ class ServiceManager(QtGui.QWidget):
|
|||
serviceitem = ServiceItem()
|
||||
serviceitem.RenderManager = self.parent.RenderManager
|
||||
serviceitem.set_from_service(item, self.servicePath)
|
||||
self.addServiceItem(serviceitem)
|
||||
if self.validateItem(serviceitem):
|
||||
self.addServiceItem(serviceitem)
|
||||
try:
|
||||
if os.path.isfile(p_file):
|
||||
os.remove(p_file)
|
||||
|
@ -516,6 +575,14 @@ class ServiceManager(QtGui.QWidget):
|
|||
self.serviceName = name[len(name) - 1]
|
||||
self.parent.serviceChanged(True, self.serviceName)
|
||||
|
||||
def validateItem(self, serviceItem):
|
||||
# print "---"
|
||||
# print serviceItem.name
|
||||
# print serviceItem.title
|
||||
# print serviceItem.service_item_path
|
||||
# print serviceItem.service_item_type
|
||||
return True
|
||||
|
||||
def cleanUp(self):
|
||||
"""
|
||||
Empties the servicePath of temporary files
|
||||
|
@ -538,13 +605,20 @@ class ServiceManager(QtGui.QWidget):
|
|||
self.regenerateServiceItems()
|
||||
|
||||
def regenerateServiceItems(self):
|
||||
if len(self.serviceItems) > 0:
|
||||
#force reset of renderer as theme data has changed
|
||||
self.parent.RenderManager.themedata = None
|
||||
if self.serviceItems:
|
||||
tempServiceItems = self.serviceItems
|
||||
self.onNewService()
|
||||
self.ServiceManagerList.clear()
|
||||
self.serviceItems = []
|
||||
self.isNew = True
|
||||
for item in tempServiceItems:
|
||||
self.addServiceItem(item[u'service_item'])
|
||||
self.addServiceItem(item[u'service_item'], False, item[u'expanded'])
|
||||
#Set to False as items may have changed rendering
|
||||
#does not impact the saved song so True may aslo be valid
|
||||
self.parent.serviceChanged(False, self.serviceName)
|
||||
|
||||
def addServiceItem(self, item):
|
||||
def addServiceItem(self, item, rebuild=False, expand=True):
|
||||
"""
|
||||
Add a Service item to the list
|
||||
|
||||
|
@ -564,13 +638,16 @@ class ServiceManager(QtGui.QWidget):
|
|||
if sitem == -1:
|
||||
self.serviceItems.append({u'service_item': item,
|
||||
u'order': len(self.serviceItems) + 1,
|
||||
u'expanded':True})
|
||||
u'expanded':expand})
|
||||
self.repaintServiceList(len(self.serviceItems) + 1, 0)
|
||||
else:
|
||||
self.serviceItems.insert(sitem + 1, {u'service_item': item,
|
||||
u'order': len(self.serviceItems)+1,
|
||||
u'expanded':True})
|
||||
u'expanded':expand})
|
||||
self.repaintServiceList(sitem + 1, 0)
|
||||
#if rebuilding list make sure live is fixed.
|
||||
if rebuild:
|
||||
self.parent.LiveController.replaceServiceManagerItem(item)
|
||||
self.parent.serviceChanged(False, self.serviceName)
|
||||
|
||||
def makePreview(self):
|
||||
|
@ -581,6 +658,7 @@ class ServiceManager(QtGui.QWidget):
|
|||
self.parent.PreviewController.addServiceManagerItem(
|
||||
self.serviceItems[item][u'service_item'], count)
|
||||
|
||||
|
||||
def makeLive(self):
|
||||
"""
|
||||
Send the current item to the Live slide controller
|
||||
|
@ -588,6 +666,13 @@ class ServiceManager(QtGui.QWidget):
|
|||
item, count = self.findServiceItem()
|
||||
self.parent.LiveController.addServiceManagerItem(
|
||||
self.serviceItems[item][u'service_item'], count)
|
||||
if str_to_bool(PluginConfig(u'General').
|
||||
get_config(u'auto preview', u'False')):
|
||||
item += 1
|
||||
if self.serviceItems and item < len(self.serviceItems) and \
|
||||
self.serviceItems[item][u'service_item'].autoPreviewAllowed:
|
||||
self.parent.PreviewController.addServiceManagerItem(
|
||||
self.serviceItems[item][u'service_item'], 0)
|
||||
|
||||
def remoteEdit(self):
|
||||
"""
|
||||
|
@ -617,7 +702,7 @@ class ServiceManager(QtGui.QWidget):
|
|||
else:
|
||||
pos = parentitem.data(0, QtCore.Qt.UserRole).toInt()[0]
|
||||
count = item.data(0, QtCore.Qt.UserRole).toInt()[0]
|
||||
#adjuest for zero based arrays
|
||||
#adjust for zero based arrays
|
||||
pos = pos - 1
|
||||
return pos, count
|
||||
|
||||
|
@ -646,7 +731,7 @@ class ServiceManager(QtGui.QWidget):
|
|||
if plugin == u'ServiceManager':
|
||||
startpos, startCount = self.findServiceItem()
|
||||
item = self.ServiceManagerList.itemAt(event.pos())
|
||||
if item == None:
|
||||
if item is None:
|
||||
endpos = len(self.serviceItems)
|
||||
else:
|
||||
parentitem = item.parent()
|
||||
|
@ -674,7 +759,7 @@ class ServiceManager(QtGui.QWidget):
|
|||
A list of current themes to be displayed
|
||||
"""
|
||||
self.ThemeComboBox.clear()
|
||||
self.ThemeMenu.clear()
|
||||
self.themeMenu.clear()
|
||||
self.ThemeComboBox.addItem(u'')
|
||||
for theme in theme_list:
|
||||
self.ThemeComboBox.addItem(theme)
|
||||
|
@ -682,7 +767,7 @@ class ServiceManager(QtGui.QWidget):
|
|||
self.ServiceManagerList,
|
||||
None,
|
||||
theme , self.onThemeChangeAction)
|
||||
self.ThemeMenu.addAction(action)
|
||||
self.themeMenu.addAction(action)
|
||||
id = self.ThemeComboBox.findText(self.service_theme,
|
||||
QtCore.Qt.MatchExactly)
|
||||
# Not Found
|
||||
|
@ -697,4 +782,4 @@ class ServiceManager(QtGui.QWidget):
|
|||
theme = unicode(self.sender().text())
|
||||
item, count = self.findServiceItem()
|
||||
self.serviceItems[item][u'service_item'].theme = theme
|
||||
self.regenerateServiceItems()
|
||||
self.regenerateServiceItems()
|
||||
|
|
|
@ -27,11 +27,11 @@ import logging
|
|||
|
||||
from PyQt4 import QtGui
|
||||
|
||||
from openlp.core.ui import GeneralTab, ThemesTab, AlertsTab
|
||||
from openlp.core.ui import GeneralTab, ThemesTab
|
||||
from openlp.core.lib import Receiver
|
||||
from settingsdialog import Ui_SettingsDialog
|
||||
|
||||
log = logging.getLogger(u'SettingsForm')
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
class SettingsForm(QtGui.QDialog, Ui_SettingsDialog):
|
||||
|
||||
|
@ -44,9 +44,6 @@ class SettingsForm(QtGui.QDialog, Ui_SettingsDialog):
|
|||
# Themes tab
|
||||
self.ThemesTab = ThemesTab(mainWindow)
|
||||
self.addTab(u'Themes', self.ThemesTab)
|
||||
# Alert tab
|
||||
self.AlertsTab = AlertsTab()
|
||||
self.addTab(u'Alerts', self.AlertsTab)
|
||||
|
||||
def addTab(self, name, tab):
|
||||
log.info(u'Adding %s tab' % tab.tabTitle)
|
||||
|
@ -73,4 +70,4 @@ class SettingsForm(QtGui.QDialog, Ui_SettingsDialog):
|
|||
|
||||
def postSetUp(self):
|
||||
for tab_index in range(0, self.SettingsTabWidget.count()):
|
||||
self.SettingsTabWidget.widget(tab_index).postSetUp()
|
||||
self.SettingsTabWidget.widget(tab_index).postSetUp()
|
||||
|
|
|
@ -30,7 +30,10 @@ import os
|
|||
from PyQt4 import QtCore, QtGui
|
||||
from PyQt4.phonon import Phonon
|
||||
|
||||
from openlp.core.lib import OpenLPToolbar, Receiver, str_to_bool, PluginConfig
|
||||
from openlp.core.lib import OpenLPToolbar, Receiver, str_to_bool, \
|
||||
PluginConfig, resize_image
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
class SlideList(QtGui.QTableWidget):
|
||||
"""
|
||||
|
@ -40,6 +43,11 @@ class SlideList(QtGui.QTableWidget):
|
|||
def __init__(self, parent=None, name=None):
|
||||
QtGui.QTableWidget.__init__(self, parent.Controller)
|
||||
self.parent = parent
|
||||
self.hotkey_map = {QtCore.Qt.Key_Return: 'servicemanager_next_item',
|
||||
QtCore.Qt.Key_Space: 'live_slidecontroller_next_noloop',
|
||||
QtCore.Qt.Key_Enter: 'live_slidecontroller_next_noloop',
|
||||
QtCore.Qt.Key_0: 'servicemanager_next_item',
|
||||
QtCore.Qt.Key_Backspace: 'live_slidecontroller_previous_noloop'}
|
||||
|
||||
def keyPressEvent(self, event):
|
||||
if type(event) == QtGui.QKeyEvent:
|
||||
|
@ -56,6 +64,9 @@ class SlideList(QtGui.QTableWidget):
|
|||
elif event.key() == QtCore.Qt.Key_PageDown:
|
||||
self.parent.onSlideSelectedLast()
|
||||
event.accept()
|
||||
elif event.key() in self.hotkey_map and self.parent.isLive:
|
||||
Receiver.send_message(self.hotkey_map[event.key()])
|
||||
event.accept()
|
||||
event.ignore()
|
||||
else:
|
||||
event.ignore()
|
||||
|
@ -65,9 +76,6 @@ class SlideController(QtGui.QWidget):
|
|||
SlideController is the slide controller widget. This widget is what the
|
||||
user uses to control the displaying of verses/slides/etc on the screen.
|
||||
"""
|
||||
global log
|
||||
log = logging.getLogger(u'SlideController')
|
||||
|
||||
def __init__(self, parent, settingsmanager, isLive=False):
|
||||
"""
|
||||
Set up the Slide Controller.
|
||||
|
@ -99,15 +107,14 @@ class SlideController(QtGui.QWidget):
|
|||
# Type label for the top of the slide controller
|
||||
self.TypeLabel = QtGui.QLabel(self.Panel)
|
||||
if self.isLive:
|
||||
self.TypeLabel.setText(u'<strong>%s</strong>' %
|
||||
self.trUtf8('Live'))
|
||||
self.TypeLabel.setText(self.trUtf8('Live'))
|
||||
self.split = 1
|
||||
prefix = u'live_slidecontroller'
|
||||
else:
|
||||
self.TypeLabel.setText(u'<strong>%s</strong>' %
|
||||
self.trUtf8('Preview'))
|
||||
self.TypeLabel.setText(self.trUtf8('Preview'))
|
||||
self.split = 0
|
||||
prefix = u'preview_slidecontroller'
|
||||
self.TypeLabel.setStyleSheet(u'font-weight: bold; font-size: 12pt;')
|
||||
self.TypeLabel.setAlignment(QtCore.Qt.AlignCenter)
|
||||
self.PanelLayout.addWidget(self.TypeLabel)
|
||||
# Splitter
|
||||
|
@ -135,6 +142,7 @@ class SlideController(QtGui.QWidget):
|
|||
self.PreviewListWidget.setEditTriggers(
|
||||
QtGui.QAbstractItemView.NoEditTriggers)
|
||||
self.PreviewListWidget.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
|
||||
self.PreviewListWidget.setAlternatingRowColors(True)
|
||||
self.ControllerLayout.addWidget(self.PreviewListWidget)
|
||||
# Build the full toolbar
|
||||
self.Toolbar = OpenLPToolbar(self)
|
||||
|
@ -163,9 +171,9 @@ class SlideController(QtGui.QWidget):
|
|||
self.Toolbar.addToolbarSeparator(u'Close Separator')
|
||||
self.blankButton = self.Toolbar.addToolbarButton(
|
||||
u'Blank Screen', u':/slides/slide_close.png',
|
||||
self.trUtf8('Blank Screen'), self.onBlankScreen, True)
|
||||
self.trUtf8('Blank Screen'), self.onBlankDisplay, True)
|
||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||
QtCore.SIGNAL(u'live_slide_blank'), self.onBlankDisplay)
|
||||
QtCore.SIGNAL(u'live_slide_blank'), self.blankScreen)
|
||||
if not self.isLive:
|
||||
self.Toolbar.addToolbarSeparator(u'Close Separator')
|
||||
self.Toolbar.addToolbarButton(
|
||||
|
@ -173,7 +181,7 @@ class SlideController(QtGui.QWidget):
|
|||
self.trUtf8('Move to live'), self.onGoLive)
|
||||
self.Toolbar.addToolbarSeparator(u'Close Separator')
|
||||
self.Toolbar.addToolbarButton(
|
||||
u'Edit Song', u':/songs/song_edit.png',
|
||||
u'Edit Song', u':/services/service_edit.png',
|
||||
self.trUtf8('Edit and re-preview Song'), self.onEditSong)
|
||||
if isLive:
|
||||
self.Toolbar.addToolbarSeparator(u'Loop Separator')
|
||||
|
@ -184,6 +192,8 @@ class SlideController(QtGui.QWidget):
|
|||
u'Stop Loop', u':/media/media_stop.png',
|
||||
self.trUtf8('Stop continuous loop'), self.onStopLoop)
|
||||
self.DelaySpinBox = QtGui.QSpinBox()
|
||||
self.DelaySpinBox.setMinimum(1)
|
||||
self.DelaySpinBox.setMaximum(180)
|
||||
self.Toolbar.addToolbarWidget(
|
||||
u'Image SpinBox', self.DelaySpinBox)
|
||||
self.DelaySpinBox.setSuffix(self.trUtf8('s'))
|
||||
|
@ -235,6 +245,9 @@ class SlideController(QtGui.QWidget):
|
|||
self.audio = Phonon.AudioOutput(Phonon.VideoCategory, self.mediaObject)
|
||||
Phonon.createPath(self.mediaObject, self.video)
|
||||
Phonon.createPath(self.mediaObject, self.audio)
|
||||
if not self.isLive:
|
||||
self.video.setGeometry(QtCore.QRect(0, 0, 300, 225))
|
||||
self.video.setVisible(False)
|
||||
self.SlideLayout.insertWidget(0, self.video)
|
||||
# Actual preview screen
|
||||
self.SlidePreview = QtGui.QLabel(self)
|
||||
|
@ -246,7 +259,8 @@ class SlideController(QtGui.QWidget):
|
|||
self.SlidePreview.sizePolicy().hasHeightForWidth())
|
||||
self.SlidePreview.setSizePolicy(sizePolicy)
|
||||
self.SlidePreview.setFixedSize(
|
||||
QtCore.QSize(self.settingsmanager.slidecontroller_image,self.settingsmanager.slidecontroller_image / 1.3 ))
|
||||
QtCore.QSize(self.settingsmanager.slidecontroller_image,
|
||||
self.settingsmanager.slidecontroller_image / 1.3 ))
|
||||
self.SlidePreview.setFrameShape(QtGui.QFrame.Box)
|
||||
self.SlidePreview.setFrameShadow(QtGui.QFrame.Plain)
|
||||
self.SlidePreview.setLineWidth(1)
|
||||
|
@ -257,8 +271,6 @@ class SlideController(QtGui.QWidget):
|
|||
# Signals
|
||||
QtCore.QObject.connect(self.PreviewListWidget,
|
||||
QtCore.SIGNAL(u'clicked(QModelIndex)'), self.onSlideSelected)
|
||||
QtCore.QObject.connect(self.PreviewListWidget,
|
||||
QtCore.SIGNAL(u'activated(QModelIndex)'), self.onSlideSelected)
|
||||
if isLive:
|
||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||
QtCore.SIGNAL(u'update_spin_delay'), self.receiveSpinDelay)
|
||||
|
@ -268,12 +280,19 @@ class SlideController(QtGui.QWidget):
|
|||
else:
|
||||
self.Toolbar.makeWidgetsInvisible(self.song_edit_list)
|
||||
self.Mediabar.setVisible(False)
|
||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||
QtCore.SIGNAL(u'stop_display_loop'), self.onStopLoop)
|
||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||
QtCore.SIGNAL(u'%s_first' % prefix), self.onSlideSelectedFirst)
|
||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||
QtCore.SIGNAL(u'%s_next' % prefix), self.onSlideSelectedNext)
|
||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||
QtCore.SIGNAL(u'%s_previous' % prefix), self.onSlideSelectedPrevious)
|
||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||
QtCore.SIGNAL(u'%s_next_noloop' % prefix), self.onSlideSelectedNextNoloop)
|
||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||
QtCore.SIGNAL(u'%s_previous_noloop' % prefix),
|
||||
self.onSlideSelectedPreviousNoloop)
|
||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||
QtCore.SIGNAL(u'%s_last' % prefix), self.onSlideSelectedLast)
|
||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||
|
@ -393,9 +412,13 @@ class SlideController(QtGui.QWidget):
|
|||
if item.is_media():
|
||||
self.onMediaStart(item)
|
||||
elif item.is_command():
|
||||
if self.isLive:
|
||||
blanked = self.blankButton.isChecked()
|
||||
else:
|
||||
blanked = False
|
||||
Receiver.send_message(u'%s_start' % item.name.lower(), \
|
||||
[item.title, item.service_item_path,
|
||||
item.get_frame_title(), slideno, self.isLive])
|
||||
item.get_frame_title(), slideno, self.isLive, blanked])
|
||||
self.displayServiceManagerItems(item, slideno)
|
||||
|
||||
def displayServiceManagerItems(self, serviceItem, slideno):
|
||||
|
@ -428,9 +451,11 @@ class SlideController(QtGui.QWidget):
|
|||
tag = None
|
||||
#If verse handle verse number else tag only
|
||||
if bits[0] == self.trUtf8('Verse'):
|
||||
tag = u'%s%s' % (bits[0][0], bits[1][0] )
|
||||
tag = u'%s%s' % (bits[0][0], bits[1][0:] )
|
||||
row = bits[1][0:]
|
||||
else:
|
||||
tag = bits[0]
|
||||
row = bits[0][0:1]
|
||||
try:
|
||||
test = self.slideList[tag]
|
||||
except:
|
||||
|
@ -441,7 +466,9 @@ class SlideController(QtGui.QWidget):
|
|||
else:
|
||||
label = QtGui.QLabel()
|
||||
label.setMargin(4)
|
||||
pixmap = self.parent.RenderManager.resize_image(frame[u'image'])
|
||||
pixmap = resize_image(frame[u'image'],
|
||||
self.parent.RenderManager.width,
|
||||
self.parent.RenderManager.height)
|
||||
label.setScaledContents(True)
|
||||
label.setPixmap(QtGui.QPixmap.fromImage(pixmap))
|
||||
self.PreviewListWidget.setCellWidget(framenumber, 0, label)
|
||||
|
@ -480,18 +507,26 @@ class SlideController(QtGui.QWidget):
|
|||
self.PreviewListWidget.selectRow(0)
|
||||
self.onSlideSelected()
|
||||
|
||||
def onBlankDisplay(self):
|
||||
self.blankButton.setChecked(self.parent.mainDisplay.displayBlank)
|
||||
def onBlankDisplay(self, force=False):
|
||||
"""
|
||||
Handle the blank screen button
|
||||
"""
|
||||
if force:
|
||||
self.blankButton.setChecked(True)
|
||||
self.blankScreen(self.blankButton.isChecked())
|
||||
self.parent.generalConfig.set_config(u'screen blank',
|
||||
self.blankButton.isChecked())
|
||||
|
||||
def onBlankScreen(self, blanked):
|
||||
def blankScreen(self, blanked=False):
|
||||
"""
|
||||
Blank the screen.
|
||||
Blank the display screen.
|
||||
"""
|
||||
if not self.serviceItem and self.serviceItem.is_command():
|
||||
if blanked:
|
||||
Receiver.send_message(u'%s_blank'% self.serviceItem.name.lower())
|
||||
else:
|
||||
Receiver.send_message(u'%s_unblank'% self.serviceItem.name.lower())
|
||||
if self.serviceItem is not None:
|
||||
if self.serviceItem.is_command():
|
||||
if blanked:
|
||||
Receiver.send_message(u'%s_blank'% self.serviceItem.name.lower())
|
||||
else:
|
||||
Receiver.send_message(u'%s_unblank'% self.serviceItem.name.lower())
|
||||
else:
|
||||
self.parent.mainDisplay.blankDisplay(blanked)
|
||||
|
||||
|
@ -531,7 +566,7 @@ class SlideController(QtGui.QWidget):
|
|||
|
||||
def updatePreview(self):
|
||||
rm = self.parent.RenderManager
|
||||
if not rm.screen_list[rm.current_display][u'primary']:
|
||||
if not rm.screens.current[u'primary']:
|
||||
# Grab now, but try again in a couple of seconds if slide change is slow
|
||||
QtCore.QTimer.singleShot(0.5, self.grabMainDisplay)
|
||||
QtCore.QTimer.singleShot(2.5, self.grabMainDisplay)
|
||||
|
@ -543,12 +578,15 @@ class SlideController(QtGui.QWidget):
|
|||
def grabMainDisplay(self):
|
||||
rm = self.parent.RenderManager
|
||||
winid = QtGui.QApplication.desktop().winId()
|
||||
rect = rm.screen_list[rm.current_display][u'size']
|
||||
rect = rm.screens.current[u'size']
|
||||
winimg = QtGui.QPixmap.grabWindow(winid, rect.x(),
|
||||
rect.y(), rect.width(), rect.height())
|
||||
self.SlidePreview.setPixmap(winimg)
|
||||
|
||||
def onSlideSelectedNext(self):
|
||||
def onSlideSelectedNextNoloop(self):
|
||||
self.onSlideSelectedNext(False)
|
||||
|
||||
def onSlideSelectedNext(self, loop=True):
|
||||
"""
|
||||
Go to the next slide.
|
||||
"""
|
||||
|
@ -561,11 +599,18 @@ class SlideController(QtGui.QWidget):
|
|||
else:
|
||||
row = self.PreviewListWidget.currentRow() + 1
|
||||
if row == self.PreviewListWidget.rowCount():
|
||||
row = 0
|
||||
if loop:
|
||||
row = 0
|
||||
else:
|
||||
Receiver.send_message('servicemanager_next_item')
|
||||
return
|
||||
self.PreviewListWidget.selectRow(row)
|
||||
self.onSlideSelected()
|
||||
|
||||
def onSlideSelectedPrevious(self):
|
||||
def onSlideSelectedPreviousNoloop(self):
|
||||
self.onSlideSelectedPrevious(False)
|
||||
|
||||
def onSlideSelectedPrevious(self, loop=True):
|
||||
"""
|
||||
Go to the previous slide.
|
||||
"""
|
||||
|
@ -578,7 +623,10 @@ class SlideController(QtGui.QWidget):
|
|||
else:
|
||||
row = self.PreviewListWidget.currentRow() - 1
|
||||
if row == -1:
|
||||
row = self.PreviewListWidget.rowCount() - 1
|
||||
if loop:
|
||||
row = self.PreviewListWidget.rowCount() - 1
|
||||
else:
|
||||
row = 0
|
||||
self.PreviewListWidget.selectRow(row)
|
||||
self.onSlideSelected()
|
||||
|
||||
|
@ -635,7 +683,7 @@ class SlideController(QtGui.QWidget):
|
|||
if self.isLive:
|
||||
Receiver.send_message(u'%s_start' % item.name.lower(), \
|
||||
[item.title, item.service_item_path,
|
||||
item.get_frame_title(), slideno, self.isLive])
|
||||
item.get_frame_title(), self.isLive, self.blankButton.isChecked()])
|
||||
else:
|
||||
self.mediaObject.stop()
|
||||
self.mediaObject.clearQueue()
|
||||
|
@ -659,9 +707,9 @@ class SlideController(QtGui.QWidget):
|
|||
|
||||
def onMediaStop(self):
|
||||
if self.isLive:
|
||||
Receiver.send_message(u'%s_stop'% self.serviceItem.name.lower())
|
||||
Receiver.send_message(u'%s_stop'% self.serviceItem.name.lower(), self.isLive)
|
||||
else:
|
||||
self.mediaObject.stop()
|
||||
self.video.hide()
|
||||
self.SlidePreview.clear()
|
||||
self.SlidePreview.show()
|
||||
self.SlidePreview.clear()
|
||||
self.SlidePreview.show()
|
||||
|
|
|
@ -34,17 +34,16 @@ from PyQt4 import QtCore, QtGui
|
|||
from openlp.core.ui import AmendThemeForm
|
||||
from openlp.core.theme import Theme
|
||||
from openlp.core.lib import PluginConfig, OpenLPToolbar, contextMenuAction, \
|
||||
ThemeXML, ThemeLevel, str_to_bool, get_text_file_string, build_icon, \
|
||||
Receiver, contextMenuSeparator
|
||||
ThemeXML, str_to_bool, get_text_file_string, build_icon, Receiver, \
|
||||
contextMenuSeparator
|
||||
from openlp.core.utils import ConfigHelper
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
class ThemeManager(QtGui.QWidget):
|
||||
"""
|
||||
Manages the orders of Theme.
|
||||
"""
|
||||
global log
|
||||
log = logging.getLogger(u'ThemeManager')
|
||||
|
||||
def __init__(self, parent):
|
||||
QtGui.QWidget.__init__(self, parent)
|
||||
self.parent = parent
|
||||
|
@ -108,6 +107,8 @@ class ThemeManager(QtGui.QWidget):
|
|||
self.themelist = []
|
||||
self.path = os.path.join(ConfigHelper.get_data_path(), u'themes')
|
||||
self.checkThemesExists(self.path)
|
||||
self.thumbPath = os.path.join(self.path, u'.thumbnails')
|
||||
self.checkThemesExists(self.thumbPath)
|
||||
self.amendThemeForm.path = self.path
|
||||
# Last little bits of setting up
|
||||
self.config = PluginConfig(u'themes')
|
||||
|
@ -179,12 +180,26 @@ class ThemeManager(QtGui.QWidget):
|
|||
self.trUtf8('You are unable to delete the default theme!'),
|
||||
QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Ok))
|
||||
else:
|
||||
for plugin in self.parent.plugin_manager.plugins:
|
||||
if not plugin.can_delete_theme(theme):
|
||||
QtGui.QMessageBox.critical(
|
||||
self, self.trUtf8('Error'),
|
||||
self.trUtf8('theme %s is use in %s plugin' % (theme, plugin.name)),
|
||||
QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Ok))
|
||||
return
|
||||
if unicode(self.parent.ServiceManagerContents.ThemeComboBox.currentText()) == theme:
|
||||
QtGui.QMessageBox.critical(
|
||||
self, self.trUtf8('Error'),
|
||||
self.trUtf8('theme %s is use Service Manager' % theme),
|
||||
QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Ok))
|
||||
return
|
||||
self.themelist.remove(theme)
|
||||
th = theme + u'.png'
|
||||
row = self.ThemeListWidget.row(item)
|
||||
self.ThemeListWidget.takeItem(row)
|
||||
try:
|
||||
os.remove(os.path.join(self.path, th))
|
||||
os.remove(os.path.join(self.thumbPath, th))
|
||||
shutil.rmtree(os.path.join(self.path, theme))
|
||||
except:
|
||||
#if not present do not worry
|
||||
|
@ -231,9 +246,9 @@ class ThemeManager(QtGui.QWidget):
|
|||
self, self.trUtf8('Select Theme Import File'),
|
||||
self.config.get_last_dir(), u'Theme (*.*)')
|
||||
log.info(u'New Themes %s', unicode(files))
|
||||
if len(files) > 0:
|
||||
if files:
|
||||
for file in files:
|
||||
self.config.set_last_dir(filename)
|
||||
self.config.set_last_dir(unicode(file))
|
||||
self.unzipTheme(file, self.path)
|
||||
self.loadThemes()
|
||||
|
||||
|
@ -246,25 +261,33 @@ class ThemeManager(QtGui.QWidget):
|
|||
log.debug(u'Load themes from dir')
|
||||
self.themelist = []
|
||||
self.ThemeListWidget.clear()
|
||||
for root, dirs, files in os.walk(self.path):
|
||||
for name in files:
|
||||
if name.endswith(u'.png'):
|
||||
#check to see file is in theme root directory
|
||||
theme = os.path.join(self.path, name)
|
||||
if os.path.exists(theme):
|
||||
(path, filename) = os.path.split(unicode(file))
|
||||
textName = os.path.splitext(name)[0]
|
||||
if textName == self.global_theme:
|
||||
name = u'%s (%s)' % (textName,
|
||||
self.trUtf8('default'))
|
||||
else:
|
||||
name = textName
|
||||
item_name = QtGui.QListWidgetItem(name)
|
||||
item_name.setIcon(build_icon(theme))
|
||||
item_name.setData(QtCore.Qt.UserRole,
|
||||
QtCore.QVariant(textName))
|
||||
self.ThemeListWidget.addItem(item_name)
|
||||
self.themelist.append(textName)
|
||||
#root, dirs, files = os.walk(self.path)
|
||||
dirList = os.listdir(self.path)
|
||||
for name in dirList:
|
||||
if name.endswith(u'.png'):
|
||||
#check to see file is in theme root directory
|
||||
theme = os.path.join(self.path, name)
|
||||
if os.path.exists(theme):
|
||||
(path, filename) = os.path.split(unicode(file))
|
||||
textName = os.path.splitext(name)[0]
|
||||
if textName == self.global_theme:
|
||||
name = u'%s (%s)' % (textName,
|
||||
self.trUtf8('default'))
|
||||
else:
|
||||
name = textName
|
||||
thumb = os.path.join(self.thumbPath, u'%s.png' % textName)
|
||||
item_name = QtGui.QListWidgetItem(name)
|
||||
if os.path.exists(thumb):
|
||||
icon = build_icon(thumb)
|
||||
else:
|
||||
icon = build_icon(theme)
|
||||
pixmap = icon.pixmap(QtCore.QSize(88,50))
|
||||
pixmap.save(thumb, u'png')
|
||||
item_name.setIcon(icon)
|
||||
item_name.setData(QtCore.Qt.UserRole,
|
||||
QtCore.QVariant(textName))
|
||||
self.ThemeListWidget.addItem(item_name)
|
||||
self.themelist.append(textName)
|
||||
self.pushThemes()
|
||||
|
||||
def pushThemes(self):
|
||||
|
@ -302,17 +325,23 @@ class ThemeManager(QtGui.QWidget):
|
|||
filexml = None
|
||||
themename = None
|
||||
for file in zip.namelist():
|
||||
if file.endswith(os.path.sep):
|
||||
theme_dir = os.path.join(dir, file)
|
||||
osfile = unicode(QtCore.QDir.toNativeSeparators(file))
|
||||
theme_dir = None
|
||||
if osfile.endswith(os.path.sep):
|
||||
theme_dir = os.path.join(dir, osfile)
|
||||
if not os.path.exists(theme_dir):
|
||||
os.mkdir(os.path.join(dir, file))
|
||||
os.mkdir(os.path.join(dir, osfile))
|
||||
else:
|
||||
fullpath = os.path.join(dir, file)
|
||||
names = file.split(os.path.sep)
|
||||
fullpath = os.path.join(dir, osfile)
|
||||
names = osfile.split(os.path.sep)
|
||||
if len(names) > 1:
|
||||
# not preview file
|
||||
if themename is None:
|
||||
themename = names[0]
|
||||
if theme_dir is None:
|
||||
theme_dir = os.path.join(dir, names[0])
|
||||
if not os.path.exists(theme_dir):
|
||||
os.mkdir(os.path.join(dir, names[0]))
|
||||
xml_data = zip.read(file)
|
||||
if os.path.splitext(file)[1].lower() in [u'.xml']:
|
||||
if self.checkVersion1(xml_data):
|
||||
|
@ -324,7 +353,7 @@ class ThemeManager(QtGui.QWidget):
|
|||
outfile = open(fullpath, u'w')
|
||||
outfile.write(filexml)
|
||||
else:
|
||||
outfile = open(fullpath, u'w')
|
||||
outfile = open(fullpath, u'wb')
|
||||
outfile.write(zip.read(file))
|
||||
self.generateAndSaveImage(dir, themename, filexml)
|
||||
except:
|
||||
|
@ -332,7 +361,7 @@ class ThemeManager(QtGui.QWidget):
|
|||
self, self.trUtf8('Error'),
|
||||
self.trUtf8('File is not a valid theme!'),
|
||||
QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Ok))
|
||||
log.exception(u'Importing theme from zip file failed')
|
||||
log.exception(u'Importing theme from zip file failed %s' % filename)
|
||||
finally:
|
||||
if zip:
|
||||
zip.close()
|
||||
|
@ -373,7 +402,6 @@ class ThemeManager(QtGui.QWidget):
|
|||
unicode(theme.BackgroundParameter2.name()), direction)
|
||||
else:
|
||||
newtheme.add_background_image(unicode(theme.BackgroundParameter1))
|
||||
|
||||
newtheme.add_font(unicode(theme.FontName),
|
||||
unicode(theme.FontColor.name()),
|
||||
unicode(theme.FontProportion * 3), u'False')
|
||||
|
@ -386,10 +414,15 @@ class ThemeManager(QtGui.QWidget):
|
|||
shadow = True
|
||||
if theme.Outline == 1:
|
||||
outline = True
|
||||
vAlignCorrection = 0
|
||||
if theme.VerticalAlign == 2:
|
||||
vAlignCorrection = 1
|
||||
elif theme.VerticalAlign == 1:
|
||||
vAlignCorrection = 2
|
||||
newtheme.add_display(unicode(shadow), unicode(theme.ShadowColor.name()),
|
||||
unicode(outline), unicode(theme.OutlineColor.name()),
|
||||
unicode(theme.HorizontalAlign), unicode(theme.VerticalAlign),
|
||||
unicode(theme.WrapStyle), 0)
|
||||
unicode(theme.HorizontalAlign), unicode(vAlignCorrection),
|
||||
unicode(theme.WrapStyle), unicode(0))
|
||||
return newtheme.extract_xml()
|
||||
|
||||
def saveTheme(self, name, theme_xml, theme_pretty_xml, image_from,
|
||||
|
@ -427,8 +460,6 @@ class ThemeManager(QtGui.QWidget):
|
|||
if outfile:
|
||||
outfile.close()
|
||||
if image_from and image_from != image_to:
|
||||
print "if", image_from
|
||||
print "it", image_to
|
||||
try:
|
||||
shutil.copyfile(image_from, image_to)
|
||||
except:
|
||||
|
@ -448,6 +479,10 @@ class ThemeManager(QtGui.QWidget):
|
|||
if os.path.exists(samplepathname):
|
||||
os.unlink(samplepathname)
|
||||
frame.save(samplepathname, u'png')
|
||||
thumb = os.path.join(self.thumbPath, u'%s.png' % name)
|
||||
icon = build_icon(frame)
|
||||
pixmap = icon.pixmap(QtCore.QSize(88,50))
|
||||
pixmap.save(thumb, u'png')
|
||||
log.debug(u'Theme image written to %s', samplepathname)
|
||||
|
||||
def generateImage(self, themedata):
|
||||
|
@ -529,4 +564,4 @@ class ThemeManager(QtGui.QWidget):
|
|||
theme.font_main_y = int(theme.font_main_y.strip())
|
||||
#theme.theme_mode
|
||||
theme.theme_name = theme.theme_name.strip()
|
||||
#theme.theme_version
|
||||
#theme.theme_version
|
||||
|
|
|
@ -22,21 +22,65 @@
|
|||
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
|
||||
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
||||
###############################################################################
|
||||
|
||||
import os
|
||||
import sys
|
||||
import logging
|
||||
import urllib2
|
||||
from datetime import datetime
|
||||
|
||||
from registry import Registry
|
||||
from confighelper import ConfigHelper
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
__all__ = ['Registry', 'ConfigHelper']
|
||||
class AppLocation(object):
|
||||
"""
|
||||
Retrieve a directory based on the directory type.
|
||||
"""
|
||||
AppDir = 1
|
||||
ConfigDir = 2
|
||||
DataDir = 3
|
||||
PluginsDir = 4
|
||||
|
||||
@staticmethod
|
||||
def get_directory(dir_type):
|
||||
if dir_type == AppLocation.AppDir:
|
||||
return os.path.abspath(os.path.split(sys.argv[0])[0])
|
||||
elif dir_type == AppLocation.ConfigDir:
|
||||
if os.name == u'nt':
|
||||
path = os.path.join(os.getenv(u'APPDATA'), u'openlp')
|
||||
elif os.name == u'mac':
|
||||
path = os.path.join(os.getenv(u'HOME'), u'Library',
|
||||
u'Application Support', u'openlp')
|
||||
else:
|
||||
try:
|
||||
from xdg import BaseDirectory
|
||||
path = os.path.join(BaseDirectory.xdg_config_home, u'openlp')
|
||||
except ImportError:
|
||||
path = os.path.join(os.getenv(u'HOME'), u'.openlp')
|
||||
return path
|
||||
elif dir_type == AppLocation.DataDir:
|
||||
if os.name == u'nt':
|
||||
path = os.path.join(os.getenv(u'APPDATA'), u'openlp', u'data')
|
||||
elif os.name == u'mac':
|
||||
path = os.path.join(os.getenv(u'HOME'), u'Library',
|
||||
u'Application Support', u'openlp', u'Data')
|
||||
else:
|
||||
try:
|
||||
from xdg import BaseDirectory
|
||||
path = os.path.join(BaseDirectory.xdg_data_home, u'openlp')
|
||||
except ImportError:
|
||||
path = os.path.join(os.getenv(u'HOME'), u'.openlp', u'data')
|
||||
return path
|
||||
elif dir_type == AppLocation.PluginsDir:
|
||||
app_path = os.path.abspath(os.path.split(sys.argv[0])[0])
|
||||
if hasattr(sys, u'frozen') and sys.frozen == 1:
|
||||
return os.path.join(app_path, u'plugins')
|
||||
else:
|
||||
return os.path.join(app_path, u'openlp', u'plugins')
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
def check_latest_version(config, current_version):
|
||||
version_string = current_version
|
||||
#set to prod in the distribution confif file.
|
||||
last_test = config.get_config(u'last version test', datetime.now().date())
|
||||
this_test = unicode(datetime.now().date())
|
||||
config.set_config(u'last version test', this_test)
|
||||
|
@ -52,3 +96,8 @@ def check_latest_version(config, current_version):
|
|||
if hasattr(e, u'reason'):
|
||||
log.exception(u'Reason for failure: %s', e.reason)
|
||||
return version_string
|
||||
|
||||
from registry import Registry
|
||||
from confighelper import ConfigHelper
|
||||
|
||||
__all__ = [u'Registry', u'ConfigHelper', u'AppLocations', u'check_latest_version']
|
||||
|
|
|
@ -24,6 +24,8 @@
|
|||
###############################################################################
|
||||
|
||||
import os
|
||||
|
||||
from openlp.core.utils import AppLocation
|
||||
from openlp.core.utils.registry import Registry
|
||||
|
||||
class ConfigHelper(object):
|
||||
|
@ -34,20 +36,7 @@ class ConfigHelper(object):
|
|||
|
||||
@staticmethod
|
||||
def get_data_path():
|
||||
if os.name == u'nt':
|
||||
# ask OS for path to application data, set on Windows XP and Vista
|
||||
path = os.path.join(os.getenv(u'APPDATA'), u'openlp', u'data')
|
||||
elif os.name == u'mac':
|
||||
path = os.path.join(os.getenv(u'HOME'), u'Library',
|
||||
u'Application Support', u'openlp', u'Data')
|
||||
else:
|
||||
try:
|
||||
from xdg import BaseDirectory
|
||||
path = os.path.join(BaseDirectory.xdg_data_home, u'openlp')
|
||||
except ImportError:
|
||||
path = os.path.join(os.getenv(u'HOME'), u'.openlp', u'data')
|
||||
#reg = ConfigHelper.get_registry()
|
||||
#path = ConfigHelper.get_config(u'main', 'data path', path)
|
||||
path = AppLocation.get_directory(AppLocation.DataDir)
|
||||
if not os.path.exists(path):
|
||||
os.makedirs(path)
|
||||
return path
|
||||
|
@ -81,17 +70,7 @@ class ConfigHelper(object):
|
|||
current operating system, and returns an instantiation of that class.
|
||||
"""
|
||||
if ConfigHelper.__registry__ is None:
|
||||
config_path = u''
|
||||
if os.name == u'nt':
|
||||
config_path = os.path.join(os.getenv(u'APPDATA'), u'openlp')
|
||||
elif os.name == u'mac':
|
||||
config_path = os.path.join(os.getenv(u'HOME'), u'Library',
|
||||
u'Application Support', u'openlp')
|
||||
else:
|
||||
try:
|
||||
from xdg import BaseDirectory
|
||||
config_path = os.path.join(BaseDirectory.xdg_config_home, u'openlp')
|
||||
except ImportError:
|
||||
config_path = os.path.join(os.getenv(u'HOME'), u'.openlp')
|
||||
config_path = AppLocation.get_directory(AppLocation.ConfigDir)
|
||||
ConfigHelper.__registry__ = Registry(config_path)
|
||||
return ConfigHelper.__registry__
|
||||
return ConfigHelper.__registry__
|
||||
|
||||
|
|
|
@ -25,18 +25,18 @@
|
|||
|
||||
import logging
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
class Display():
|
||||
global log
|
||||
log = logging.getLogger(u'Display Logger')
|
||||
log.info(u'Display Class loaded')
|
||||
|
||||
@staticmethod
|
||||
def output(string):
|
||||
log.debug(string);
|
||||
print (string)
|
||||
log.debug(string)
|
||||
#print (string)
|
||||
|
||||
@staticmethod
|
||||
def sub_output(string):
|
||||
if not string is None:
|
||||
log.debug(u' '+string);
|
||||
print (u' '+string)
|
||||
log.debug(u' '+string)
|
||||
#print (u' '+string)
|
||||
|
|
|
@ -28,5 +28,5 @@ class MigrateBibles():
|
|||
self.display = display
|
||||
|
||||
def process(self):
|
||||
self.display.output(u'Bible process started');
|
||||
self.display.output(u'Bible process finished');
|
||||
self.display.output(u'Bible process started')
|
||||
self.display.output(u'Bible process finished')
|
|
@ -30,20 +30,20 @@ class MigrateFiles():
|
|||
self.display = display
|
||||
|
||||
def process(self):
|
||||
self.display.output(u'Files process started');
|
||||
self.display.output(u'Files process started')
|
||||
self._initial_setup()
|
||||
self.display.output(u'Files process finished');
|
||||
self.display.output(u'Files process finished')
|
||||
|
||||
def _initial_setup(self):
|
||||
self.display.output(u'Initial Setup started');
|
||||
self.display.output(u'Initial Setup started')
|
||||
ConfigHelper.get_data_path()
|
||||
self.display.sub_output(u'Config created');
|
||||
self.display.sub_output(u'Config created')
|
||||
ConfigHelper.get_config(u'bible', u'data path')
|
||||
self.display.sub_output(u'Config created');
|
||||
self.display.sub_output(u'Config created')
|
||||
ConfigHelper.get_config(u'videos', u'data path')
|
||||
self.display.sub_output(u'videos created');
|
||||
self.display.sub_output(u'videos created')
|
||||
ConfigHelper.get_config(u'images', u'data path')
|
||||
self.display.sub_output(u'images created');
|
||||
self.display.sub_output(u'images created')
|
||||
ConfigHelper.get_config(u'presentations', u'data path')
|
||||
self.display.sub_output(u'presentations created');
|
||||
self.display.output(u'Initial Setup finished');
|
||||
self.display.sub_output(u'presentations created')
|
||||
self.display.output(u'Initial Setup finished')
|
|
@ -0,0 +1,24 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
|
||||
|
||||
###############################################################################
|
||||
# OpenLP - Open Source Lyrics Projection #
|
||||
# --------------------------------------------------------------------------- #
|
||||
# Copyright (c) 2008-2010 Raoul Snyman #
|
||||
# Portions copyright (c) 2008-2010 Tim Bentley, Jonathan Corwin, Michael #
|
||||
# Gorven, Scott Guerrieri, Maikel Stuivenberg, Martin Thompson, Jon Tibble, #
|
||||
# Carsten Tinggaard #
|
||||
# --------------------------------------------------------------------------- #
|
||||
# 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 #
|
||||
###############################################################################
|
|
@ -0,0 +1,100 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
|
||||
|
||||
###############################################################################
|
||||
# OpenLP - Open Source Lyrics Projection #
|
||||
# --------------------------------------------------------------------------- #
|
||||
# Copyright (c) 2008-2010 Raoul Snyman #
|
||||
# Portions copyright (c) 2008-2010 Tim Bentley, Jonathan Corwin, Michael #
|
||||
# Gorven, Scott Guerrieri, Maikel Stuivenberg, Martin Thompson, Jon Tibble, #
|
||||
# Carsten Tinggaard #
|
||||
# --------------------------------------------------------------------------- #
|
||||
# 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
|
||||
|
||||
from PyQt4 import QtCore, QtGui
|
||||
|
||||
from openlp.core.lib import Plugin, build_icon, PluginStatus
|
||||
from openlp.plugins.alerts.lib import AlertsManager, DBManager
|
||||
from openlp.plugins.alerts.forms import AlertsTab, AlertForm, AlertEditForm
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
class alertsPlugin(Plugin):
|
||||
log.info(u'Alerts Plugin loaded')
|
||||
|
||||
def __init__(self, plugin_helpers):
|
||||
Plugin.__init__(self, u'Alerts', u'1.9.1', plugin_helpers)
|
||||
self.weight = -3
|
||||
self.icon = build_icon(u':/media/media_image.png')
|
||||
self.alertsmanager = AlertsManager(self)
|
||||
self.manager = DBManager(self.config)
|
||||
self.alertForm = AlertForm(self.manager, self)
|
||||
self.alertEditForm = AlertEditForm(self.manager, self)
|
||||
self.status = PluginStatus.Active
|
||||
|
||||
def get_settings_tab(self):
|
||||
self.alertsTab = AlertsTab(self)
|
||||
return self.alertsTab
|
||||
|
||||
def add_tools_menu_item(self, tools_menu):
|
||||
"""
|
||||
Give the alerts plugin the opportunity to add items to the
|
||||
**Tools** menu.
|
||||
|
||||
``tools_menu``
|
||||
The actual **Tools** menu item, so that your actions can
|
||||
use it as their parent.
|
||||
"""
|
||||
log.info(u'add tools menu')
|
||||
self.toolsAlertItem = QtGui.QAction(tools_menu)
|
||||
AlertIcon = build_icon(u':/tools/tools_alert.png')
|
||||
self.toolsAlertItem.setIcon(AlertIcon)
|
||||
self.toolsAlertItem.setObjectName(u'toolsAlertItem')
|
||||
self.toolsAlertItem.setText(self.trUtf8('&Alert'))
|
||||
self.toolsAlertItem.setStatusTip(self.trUtf8('Show an alert message'))
|
||||
self.toolsAlertItem.setShortcut(u'F7')
|
||||
self.service_manager.parent.ToolsMenu.addAction(self.toolsAlertItem)
|
||||
QtCore.QObject.connect(self.toolsAlertItem,
|
||||
QtCore.SIGNAL(u'triggered()'), self.onAlertsTrigger)
|
||||
self.toolsAlertItem.setVisible(False)
|
||||
|
||||
def initialise(self):
|
||||
log.info(u'Alerts Initialising')
|
||||
Plugin.initialise(self)
|
||||
self.toolsAlertItem.setVisible(True)
|
||||
|
||||
def finalise(self):
|
||||
log.info(u'Plugin Finalise')
|
||||
self.toolsAlertItem.setVisible(False)
|
||||
#stop any events being processed
|
||||
|
||||
def togglealertsState(self):
|
||||
self.alertsActive = not self.alertsActive
|
||||
self.config.set_config(u'active', self.alertsActive)
|
||||
|
||||
def onAlertsTrigger(self):
|
||||
self.alertForm.loadList()
|
||||
self.alertForm.exec_()
|
||||
|
||||
def onAlertsEdit(self):
|
||||
self.alertEditForm.loadList()
|
||||
self.alertEditForm.exec_()
|
||||
|
||||
def about(self):
|
||||
about_text = self.trUtf8('<b>Alerts Plugin</b><br>This plugin '
|
||||
'controls the displaying of alerts on the presentations screen')
|
||||
return about_text
|
|
@ -0,0 +1,28 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
|
||||
|
||||
###############################################################################
|
||||
# OpenLP - Open Source Lyrics Projection #
|
||||
# --------------------------------------------------------------------------- #
|
||||
# Copyright (c) 2008-2010 Raoul Snyman #
|
||||
# Portions copyright (c) 2008-2010 Tim Bentley, Jonathan Corwin, Michael #
|
||||
# Gorven, Scott Guerrieri, Maikel Stuivenberg, Martin Thompson, Jon Tibble, #
|
||||
# Carsten Tinggaard #
|
||||
# --------------------------------------------------------------------------- #
|
||||
# This program is free software; you can redistribute it and/or modify it #
|
||||
# under the terms of the GNU General Public License as published by the Free #
|
||||
# Software Foundation; version 2 of the License. #
|
||||
# #
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT #
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
|
||||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
|
||||
# more details. #
|
||||
# #
|
||||
# You should have received a copy of the GNU General Public License along #
|
||||
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
|
||||
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
||||
###############################################################################
|
||||
|
||||
from alertstab import AlertsTab
|
||||
from alertform import AlertForm
|
||||
from alerteditform import AlertEditForm
|
|
@ -0,0 +1,71 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Form implementation generated from reading ui file 'alertform.ui'
|
||||
#
|
||||
# Created: Sat Feb 13 08:19:51 2010
|
||||
# by: PyQt4 UI code generator 4.6.2
|
||||
#
|
||||
# WARNING! All changes made in this file will be lost!
|
||||
|
||||
from PyQt4 import QtCore, QtGui
|
||||
|
||||
class Ui_AlertDialog(object):
|
||||
def setupUi(self, AlertForm):
|
||||
AlertForm.setObjectName(u'AlertDialog')
|
||||
AlertForm.resize(430, 320)
|
||||
icon = QtGui.QIcon()
|
||||
icon.addPixmap(QtGui.QPixmap(u':/icon/openlp.org-icon-32.bmp'), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
||||
AlertForm.setWindowIcon(icon)
|
||||
self.AlertFormLayout = QtGui.QVBoxLayout(AlertForm)
|
||||
self.AlertFormLayout.setSpacing(8)
|
||||
self.AlertFormLayout.setMargin(8)
|
||||
self.AlertFormLayout.setObjectName(u'AlertFormLayout')
|
||||
self.AlertEntryWidget = QtGui.QWidget(AlertForm)
|
||||
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Preferred)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(self.AlertEntryWidget.sizePolicy().hasHeightForWidth())
|
||||
self.AlertEntryWidget.setSizePolicy(sizePolicy)
|
||||
self.AlertEntryWidget.setObjectName(u'AlertEntryWidget')
|
||||
self.verticalLayout_2 = QtGui.QVBoxLayout(self.AlertEntryWidget)
|
||||
self.verticalLayout_2.setObjectName(u'verticalLayout_2')
|
||||
self.verticalLayout = QtGui.QVBoxLayout()
|
||||
self.verticalLayout.setObjectName(u'verticalLayout')
|
||||
self.AlertEntryLabel = QtGui.QLabel(self.AlertEntryWidget)
|
||||
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Fixed)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(self.AlertEntryLabel.sizePolicy().hasHeightForWidth())
|
||||
self.AlertEntryLabel.setSizePolicy(sizePolicy)
|
||||
self.AlertEntryLabel.setObjectName(u'AlertEntryLabel')
|
||||
self.verticalLayout.addWidget(self.AlertEntryLabel)
|
||||
self.AlertEntryEditItem = QtGui.QLineEdit(self.AlertEntryWidget)
|
||||
self.AlertEntryEditItem.setObjectName(u'AlertEntryEditItem')
|
||||
self.verticalLayout.addWidget(self.AlertEntryEditItem)
|
||||
self.AlertListWidget = QtGui.QListWidget(self.AlertEntryWidget)
|
||||
self.AlertListWidget.setAlternatingRowColors(True)
|
||||
self.AlertListWidget.setObjectName(u'AlertListWidget')
|
||||
self.verticalLayout.addWidget(self.AlertListWidget)
|
||||
self.verticalLayout_2.addLayout(self.verticalLayout)
|
||||
self.horizontalLayout = QtGui.QHBoxLayout()
|
||||
self.horizontalLayout.setObjectName(u'horizontalLayout')
|
||||
spacerItem = QtGui.QSpacerItem(181, 38, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
|
||||
self.horizontalLayout.addItem(spacerItem)
|
||||
self.DisplayButton = QtGui.QPushButton(self.AlertEntryWidget)
|
||||
self.DisplayButton.setObjectName(u'DisplayButton')
|
||||
self.horizontalLayout.addWidget(self.DisplayButton)
|
||||
self.CancelButton = QtGui.QPushButton(self.AlertEntryWidget)
|
||||
self.CancelButton.setObjectName(u'CancelButton')
|
||||
self.horizontalLayout.addWidget(self.CancelButton)
|
||||
self.verticalLayout_2.addLayout(self.horizontalLayout)
|
||||
self.AlertFormLayout.addWidget(self.AlertEntryWidget)
|
||||
|
||||
self.retranslateUi(AlertForm)
|
||||
QtCore.QObject.connect(self.CancelButton, QtCore.SIGNAL(u'clicked()'), self.close)
|
||||
QtCore.QMetaObject.connectSlotsByName(AlertForm)
|
||||
|
||||
def retranslateUi(self, AlertForm):
|
||||
AlertForm.setWindowTitle(self.trUtf8('Alert Message'))
|
||||
self.AlertEntryLabel.setText(self.trUtf8('Alert Text:'))
|
||||
self.DisplayButton.setText(self.trUtf8('Display'))
|
||||
self.CancelButton.setText(self.trUtf8('Cancel'))
|
|
@ -0,0 +1,67 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Form implementation generated from reading ui file 'alerteditdialog.ui'
|
||||
#
|
||||
# Created: Sun Feb 14 16:45:10 2010
|
||||
# by: PyQt4 UI code generator 4.6.2
|
||||
#
|
||||
# WARNING! All changes made in this file will be lost!
|
||||
|
||||
from PyQt4 import QtCore, QtGui
|
||||
|
||||
class Ui_AlertEditDialog(object):
|
||||
def setupUi(self, AlertEditDialog):
|
||||
AlertEditDialog.setObjectName(u'AlertEditDialog')
|
||||
AlertEditDialog.resize(400, 300)
|
||||
self.buttonBox = QtGui.QDialogButtonBox(AlertEditDialog)
|
||||
self.buttonBox.setGeometry(QtCore.QRect(220, 270, 173, 27))
|
||||
self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Cancel)
|
||||
self.buttonBox.setObjectName(u'buttonBox')
|
||||
self.layoutWidget = QtGui.QWidget(AlertEditDialog)
|
||||
self.layoutWidget.setGeometry(QtCore.QRect(20, 10, 361, 251))
|
||||
self.layoutWidget.setObjectName(u'layoutWidget')
|
||||
self.verticalLayout_2 = QtGui.QVBoxLayout(self.layoutWidget)
|
||||
self.verticalLayout_2.setObjectName(u'verticalLayout_2')
|
||||
self.horizontalLayout_2 = QtGui.QHBoxLayout()
|
||||
self.horizontalLayout_2.setObjectName(u'horizontalLayout_2')
|
||||
self.AlertLineEdit = QtGui.QLineEdit(self.layoutWidget)
|
||||
self.AlertLineEdit.setObjectName(u'AlertLineEdit')
|
||||
self.horizontalLayout_2.addWidget(self.AlertLineEdit)
|
||||
self.verticalLayout_2.addLayout(self.horizontalLayout_2)
|
||||
self.horizontalLayout = QtGui.QHBoxLayout()
|
||||
self.horizontalLayout.setObjectName(u'horizontalLayout')
|
||||
self.AlertListWidget = QtGui.QListWidget(self.layoutWidget)
|
||||
self.AlertListWidget.setAlternatingRowColors(True)
|
||||
self.AlertListWidget.setObjectName(u'AlertListWidget')
|
||||
self.horizontalLayout.addWidget(self.AlertListWidget)
|
||||
self.verticalLayout = QtGui.QVBoxLayout()
|
||||
self.verticalLayout.setObjectName(u'verticalLayout')
|
||||
self.SaveButton = QtGui.QPushButton(self.layoutWidget)
|
||||
self.SaveButton.setObjectName(u'SaveButton')
|
||||
self.verticalLayout.addWidget(self.SaveButton)
|
||||
self.ClearButton = QtGui.QPushButton(self.layoutWidget)
|
||||
self.ClearButton.setObjectName(u'ClearButton')
|
||||
self.verticalLayout.addWidget(self.ClearButton)
|
||||
self.AddButton = QtGui.QPushButton(self.layoutWidget)
|
||||
self.AddButton.setObjectName(u'AddButton')
|
||||
self.verticalLayout.addWidget(self.AddButton)
|
||||
self.EditButton = QtGui.QPushButton(self.layoutWidget)
|
||||
self.EditButton.setObjectName(u'EditButton')
|
||||
self.verticalLayout.addWidget(self.EditButton)
|
||||
self.DeleteButton = QtGui.QPushButton(self.layoutWidget)
|
||||
self.DeleteButton.setObjectName(u'DeleteButton')
|
||||
self.verticalLayout.addWidget(self.DeleteButton)
|
||||
self.horizontalLayout.addLayout(self.verticalLayout)
|
||||
self.verticalLayout_2.addLayout(self.horizontalLayout)
|
||||
|
||||
self.retranslateUi(AlertEditDialog)
|
||||
QtCore.QMetaObject.connectSlotsByName(AlertEditDialog)
|
||||
|
||||
def retranslateUi(self, AlertEditDialog):
|
||||
AlertEditDialog.setWindowTitle(self.trUtf8('Maintain Alerts'))
|
||||
self.SaveButton.setText(self.trUtf8('Save'))
|
||||
self.ClearButton.setText(self.trUtf8('Clear'))
|
||||
self.AddButton.setText(self.trUtf8('Add'))
|
||||
self.EditButton.setText(self.trUtf8('Edit'))
|
||||
self.DeleteButton.setText(self.trUtf8('Delete'))
|
||||
|
|
@ -0,0 +1,166 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
|
||||
|
||||
###############################################################################
|
||||
# OpenLP - Open Source Lyrics Projection #
|
||||
# --------------------------------------------------------------------------- #
|
||||
# Copyright (c) 2008-2010 Raoul Snyman #
|
||||
# Portions copyright (c) 2008-2010 Tim Bentley, Jonathan Corwin, Michael #
|
||||
# Gorven, Scott Guerrieri, Maikel Stuivenberg, Martin Thompson, Jon Tibble, #
|
||||
# Carsten Tinggaard #
|
||||
# --------------------------------------------------------------------------- #
|
||||
# This program is free software; you can redistribute it and/or modify it #
|
||||
# under the terms of the GNU General Public License as published by the Free #
|
||||
# Software Foundation; version 2 of the License. #
|
||||
# #
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT #
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
|
||||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
|
||||
# more details. #
|
||||
# #
|
||||
# You should have received a copy of the GNU General Public License along #
|
||||
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
|
||||
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
||||
###############################################################################
|
||||
|
||||
from PyQt4 import QtGui, QtCore
|
||||
from openlp.plugins.alerts.lib.models import AlertItem
|
||||
|
||||
from alerteditdialog import Ui_AlertEditDialog
|
||||
|
||||
class AlertEditForm(QtGui.QDialog, Ui_AlertEditDialog):
|
||||
"""
|
||||
Class documentation goes here.
|
||||
"""
|
||||
def __init__(self, manager, parent):
|
||||
"""
|
||||
Constructor
|
||||
"""
|
||||
self.manager = manager
|
||||
self.parent = parent
|
||||
QtGui.QDialog.__init__(self, None)
|
||||
self.setupUi(self)
|
||||
QtCore.QObject.connect(self.DeleteButton,
|
||||
QtCore.SIGNAL(u'clicked()'),
|
||||
self.onDeleteClick)
|
||||
QtCore.QObject.connect(self.ClearButton,
|
||||
QtCore.SIGNAL(u'clicked()'),
|
||||
self.onClearClick)
|
||||
QtCore.QObject.connect(self.EditButton,
|
||||
QtCore.SIGNAL(u'clicked()'),
|
||||
self.onEditClick)
|
||||
QtCore.QObject.connect(self.AddButton,
|
||||
QtCore.SIGNAL(u'clicked()'),
|
||||
self.onAddClick)
|
||||
QtCore.QObject.connect(self.SaveButton,
|
||||
QtCore.SIGNAL(u'clicked()'),
|
||||
self.onSaveClick)
|
||||
QtCore.QObject.connect(self.buttonBox,
|
||||
QtCore.SIGNAL(u'rejected()'), self.close)
|
||||
QtCore.QObject.connect(self.AlertLineEdit,
|
||||
QtCore.SIGNAL(u'textChanged(const QString&)'),
|
||||
self.onTextChanged)
|
||||
QtCore.QObject.connect(self.AlertListWidget,
|
||||
QtCore.SIGNAL(u'doubleClicked(QModelIndex)'),
|
||||
self.onItemSelected)
|
||||
QtCore.QObject.connect(self.AlertListWidget,
|
||||
QtCore.SIGNAL(u'clicked(QModelIndex)'),
|
||||
self.onItemSelected)
|
||||
|
||||
def loadList(self):
|
||||
self.AlertListWidget.clear()
|
||||
alerts = self.manager.get_all_alerts()
|
||||
for alert in alerts:
|
||||
item_name = QtGui.QListWidgetItem(alert.text)
|
||||
item_name.setData(
|
||||
QtCore.Qt.UserRole, QtCore.QVariant(alert.id))
|
||||
self.AlertListWidget.addItem(item_name)
|
||||
self.AddButton.setEnabled(True)
|
||||
self.ClearButton.setEnabled(False)
|
||||
self.SaveButton.setEnabled(False)
|
||||
self.EditButton.setEnabled(False)
|
||||
self.DeleteButton.setEnabled(False)
|
||||
|
||||
def onItemSelected(self):
|
||||
if self.AlertLineEdit.text():
|
||||
QtGui.QMessageBox.information(self,
|
||||
self.trUtf8('Item selected to Edit'),
|
||||
self.trUtf8('Please Save or Clear seletced item'))
|
||||
else:
|
||||
self.EditButton.setEnabled(True)
|
||||
self.DeleteButton.setEnabled(True)
|
||||
|
||||
def onDeleteClick(self):
|
||||
item = self.AlertListWidget.currentItem()
|
||||
if item:
|
||||
item_id = (item.data(QtCore.Qt.UserRole)).toInt()[0]
|
||||
self.parent.manager.delete_alert(item_id)
|
||||
row = self.AlertListWidget.row(item)
|
||||
self.AlertListWidget.takeItem(row)
|
||||
self.AddButton.setEnabled(True)
|
||||
self.SaveButton.setEnabled(False)
|
||||
self.DeleteButton.setEnabled(False)
|
||||
self.EditButton.setEnabled(False)
|
||||
|
||||
def onEditClick(self):
|
||||
item = self.AlertListWidget.currentItem()
|
||||
if item:
|
||||
self.item_id = (item.data(QtCore.Qt.UserRole)).toInt()[0]
|
||||
self.AlertLineEdit.setText(unicode(item.text()))
|
||||
self.AddButton.setEnabled(True)
|
||||
self.ClearButton.setEnabled(True)
|
||||
self.SaveButton.setEnabled(True)
|
||||
self.DeleteButton.setEnabled(True)
|
||||
self.EditButton.setEnabled(False)
|
||||
|
||||
def onClearClick(self):
|
||||
self.AlertLineEdit.setText(u'')
|
||||
self.AddButton.setEnabled(False)
|
||||
self.ClearButton.setEnabled(True)
|
||||
self.SaveButton.setEnabled(False)
|
||||
self.DeleteButton.setEnabled(False)
|
||||
self.EditButton.setEnabled(False)
|
||||
|
||||
def onAddClick(self):
|
||||
if len(self.AlertLineEdit.text()) == 0:
|
||||
QtGui.QMessageBox.information(self,
|
||||
self.trUtf8('Item selected to Add'),
|
||||
self.trUtf8('Missing data'))
|
||||
else:
|
||||
alert = AlertItem()
|
||||
alert.text = unicode(self.AlertLineEdit.text())
|
||||
self.manager.save_alert(alert)
|
||||
self.onClearClick()
|
||||
self.loadList()
|
||||
|
||||
def onSaveClick(self):
|
||||
alert = self.manager.get_alert(self.item_id)
|
||||
alert.text = unicode(self.AlertLineEdit.text())
|
||||
self.manager.save_alert(alert)
|
||||
self.onClearClick()
|
||||
self.loadList()
|
||||
|
||||
def onTextChanged(self):
|
||||
self.AddButton.setEnabled(True)
|
||||
|
||||
def onDoubleClick(self):
|
||||
"""
|
||||
List item has been double clicked to display it
|
||||
"""
|
||||
items = self.AlertListWidget.selectedIndexes()
|
||||
for item in items:
|
||||
bitem = self.AlertListWidget.item(item.row())
|
||||
self.triggerAlert(bitem.text())
|
||||
|
||||
def onSingleClick(self):
|
||||
"""
|
||||
List item has been single clicked to add it to
|
||||
the edit field so it can be changed.
|
||||
"""
|
||||
items = self.AlertListWidget.selectedIndexes()
|
||||
for item in items:
|
||||
bitem = self.AlertListWidget.item(item.row())
|
||||
self.AlertEntryEditItem.setText(bitem.text())
|
||||
|
||||
def triggerAlert(self, text):
|
||||
self.parent.alertsmanager.displayAlert(text)
|
|
@ -0,0 +1,100 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
|
||||
|
||||
###############################################################################
|
||||
# OpenLP - Open Source Lyrics Projection #
|
||||
# --------------------------------------------------------------------------- #
|
||||
# Copyright (c) 2008-2010 Raoul Snyman #
|
||||
# Portions copyright (c) 2008-2010 Tim Bentley, Jonathan Corwin, Michael #
|
||||
# Gorven, Scott Guerrieri, Maikel Stuivenberg, Martin Thompson, Jon Tibble, #
|
||||
# Carsten Tinggaard #
|
||||
# --------------------------------------------------------------------------- #
|
||||
# This program is free software; you can redistribute it and/or modify it #
|
||||
# under the terms of the GNU General Public License as published by the Free #
|
||||
# Software Foundation; version 2 of the License. #
|
||||
# #
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT #
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
|
||||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
|
||||
# more details. #
|
||||
# #
|
||||
# You should have received a copy of the GNU General Public License along #
|
||||
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
|
||||
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
||||
###############################################################################
|
||||
|
||||
from PyQt4 import QtGui, QtCore
|
||||
|
||||
from openlp.plugins.alerts.lib.models import AlertItem
|
||||
|
||||
from alertdialog import Ui_AlertDialog
|
||||
|
||||
class AlertForm(QtGui.QDialog, Ui_AlertDialog):
|
||||
"""
|
||||
Class documentation goes here.
|
||||
"""
|
||||
def __init__(self, manager, parent):
|
||||
"""
|
||||
Constructor
|
||||
"""
|
||||
self.manager = manager
|
||||
self.parent = parent
|
||||
self.history_required = True
|
||||
QtGui.QDialog.__init__(self, None)
|
||||
self.setupUi(self)
|
||||
QtCore.QObject.connect(self.DisplayButton,
|
||||
QtCore.SIGNAL(u'clicked()'),
|
||||
self.onDisplayClicked)
|
||||
QtCore.QObject.connect(self.AlertEntryEditItem,
|
||||
QtCore.SIGNAL(u'textChanged(const QString&)'),
|
||||
self.onTextChanged)
|
||||
QtCore.QObject.connect(self.AlertListWidget,
|
||||
QtCore.SIGNAL(u'doubleClicked(QModelIndex)'),
|
||||
self.onDoubleClick)
|
||||
QtCore.QObject.connect(self.AlertListWidget,
|
||||
QtCore.SIGNAL(u'clicked(QModelIndex)'),
|
||||
self.onSingleClick)
|
||||
|
||||
def loadList(self):
|
||||
self.AlertListWidget.clear()
|
||||
alerts = self.manager.get_all_alerts()
|
||||
for alert in alerts:
|
||||
item_name = QtGui.QListWidgetItem(alert.text)
|
||||
self.AlertListWidget.addItem(item_name)
|
||||
|
||||
def onDisplayClicked(self):
|
||||
self.triggerAlert(unicode(self.AlertEntryEditItem.text()))
|
||||
if self.parent.alertsTab.save_history and self.history_required:
|
||||
alert = AlertItem()
|
||||
alert.text = unicode(self.AlertEntryEditItem.text())
|
||||
self.manager.save_alert(alert)
|
||||
self.history_required = False
|
||||
self.loadList()
|
||||
|
||||
def onTextChanged(self):
|
||||
#Data has changed by editing it so potential storage
|
||||
self.history_required = True
|
||||
|
||||
def onDoubleClick(self):
|
||||
"""
|
||||
List item has been double clicked to display it
|
||||
"""
|
||||
items = self.AlertListWidget.selectedIndexes()
|
||||
for item in items:
|
||||
bitem = self.AlertListWidget.item(item.row())
|
||||
self.triggerAlert(bitem.text())
|
||||
self.history_required = False
|
||||
|
||||
def onSingleClick(self):
|
||||
"""
|
||||
List item has been single clicked to add it to
|
||||
the edit field so it can be changed.
|
||||
"""
|
||||
items = self.AlertListWidget.selectedIndexes()
|
||||
for item in items:
|
||||
bitem = self.AlertListWidget.item(item.row())
|
||||
self.AlertEntryEditItem.setText(bitem.text())
|
||||
self.history_required = False
|
||||
|
||||
def triggerAlert(self, text):
|
||||
self.parent.alertsmanager.displayAlert(text)
|
|
@ -25,16 +25,15 @@
|
|||
|
||||
from PyQt4 import QtCore, QtGui
|
||||
|
||||
from openlp.core.lib import SettingsTab
|
||||
from openlp.core.lib import SettingsTab, str_to_bool
|
||||
|
||||
class AlertsTab(SettingsTab):
|
||||
"""
|
||||
AlertsTab is the alerts settings tab in the settings dialog.
|
||||
"""
|
||||
def __init__(self):
|
||||
SettingsTab.__init__(self, u'Alerts')
|
||||
self.font_color = '#ffffff'
|
||||
self.bg_color = '#660000'
|
||||
def __init__(self, parent, section=None):
|
||||
self.parent = parent
|
||||
SettingsTab.__init__(self, parent.name, section)
|
||||
|
||||
def setupUi(self):
|
||||
self.setObjectName(u'AlertsTab')
|
||||
|
@ -83,6 +82,22 @@ class AlertsTab(SettingsTab):
|
|||
self.BackgroundColorButton.setObjectName(u'BackgroundColorButton')
|
||||
self.ColorLayout.addWidget(self.BackgroundColorButton)
|
||||
self.FontLayout.addWidget(self.ColorWidget)
|
||||
self.FontSizeWidget = QtGui.QWidget(self.FontGroupBox)
|
||||
self.FontSizeWidget.setObjectName(u'FontSizeWidget')
|
||||
self.FontSizeLayout = QtGui.QHBoxLayout(self.FontSizeWidget)
|
||||
self.FontSizeLayout.setSpacing(8)
|
||||
self.FontSizeLayout.setMargin(0)
|
||||
self.FontSizeLayout.setObjectName(u'FontSizeLayout')
|
||||
self.FontSizeLabel = QtGui.QLabel(self.FontSizeWidget)
|
||||
self.FontSizeLabel.setObjectName(u'FontSizeLabel')
|
||||
self.FontSizeLayout.addWidget(self.FontSizeLabel)
|
||||
self.FontSizeSpinBox = QtGui.QSpinBox(self.FontSizeWidget)
|
||||
self.FontSizeSpinBox.setObjectName(u'FontSizeSpinBox')
|
||||
self.FontSizeLayout.addWidget(self.FontSizeSpinBox)
|
||||
self.FontSizeSpacer = QtGui.QSpacerItem(147, 20,
|
||||
QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
|
||||
self.FontSizeLayout.addItem(self.FontSizeSpacer)
|
||||
self.FontLayout.addWidget(self.FontSizeWidget)
|
||||
self.TimeoutWidget = QtGui.QWidget(self.FontGroupBox)
|
||||
self.TimeoutWidget.setObjectName(u'TimeoutWidget')
|
||||
self.TimeoutLayout = QtGui.QHBoxLayout(self.TimeoutWidget)
|
||||
|
@ -100,6 +115,56 @@ class AlertsTab(SettingsTab):
|
|||
QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
|
||||
self.TimeoutLayout.addItem(self.TimeoutSpacer)
|
||||
self.FontLayout.addWidget(self.TimeoutWidget)
|
||||
self.LocationWidget = QtGui.QWidget(self.FontGroupBox)
|
||||
self.LocationWidget.setObjectName(u'LocationWidget')
|
||||
self.LocationLayout = QtGui.QHBoxLayout(self.LocationWidget)
|
||||
self.LocationLayout.setSpacing(8)
|
||||
self.LocationLayout.setMargin(0)
|
||||
self.LocationLayout.setObjectName(u'LocationLayout')
|
||||
self.LocationLabel = QtGui.QLabel(self.LocationWidget)
|
||||
self.LocationLabel.setObjectName(u'LocationLabel')
|
||||
self.LocationLayout.addWidget(self.LocationLabel)
|
||||
self.LocationComboBox = QtGui.QComboBox(self.LocationWidget)
|
||||
self.LocationComboBox.addItem(QtCore.QString())
|
||||
self.LocationComboBox.addItem(QtCore.QString())
|
||||
self.LocationComboBox.setObjectName(u'LocationComboBox')
|
||||
self.LocationLayout.addWidget(self.LocationComboBox)
|
||||
self.LocationSpacer = QtGui.QSpacerItem(147, 20,
|
||||
QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
|
||||
self.LocationLayout.addItem(self.LocationSpacer)
|
||||
self.FontLayout.addWidget(self.LocationWidget)
|
||||
self.HistoryWidget = QtGui.QWidget(self.FontGroupBox)
|
||||
self.HistoryWidget.setObjectName(u'HistoryWidget')
|
||||
self.HistoryLayout = QtGui.QHBoxLayout(self.HistoryWidget)
|
||||
self.HistoryLayout.setSpacing(8)
|
||||
self.HistoryLayout.setMargin(0)
|
||||
self.HistoryLayout.setObjectName(u'HistoryLayout')
|
||||
self.HistoryLabel = QtGui.QLabel(self.HistoryWidget)
|
||||
self.HistoryLabel.setObjectName(u'HistoryLabel')
|
||||
self.HistoryLayout.addWidget(self.HistoryLabel)
|
||||
self.HistoryCheckBox = QtGui.QCheckBox(self.HistoryWidget)
|
||||
self.HistoryCheckBox.setObjectName(u'HistoryCheckBox')
|
||||
self.HistoryLayout.addWidget(self.HistoryCheckBox)
|
||||
self.HistorySpacer = QtGui.QSpacerItem(147, 20,
|
||||
QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
|
||||
self.HistoryLayout.addItem(self.HistorySpacer)
|
||||
self.FontLayout.addWidget(self.HistoryWidget)
|
||||
self.HistoryEditWidget = QtGui.QWidget(self.FontGroupBox)
|
||||
self.HistoryEditWidget.setObjectName(u'HistoryEditWidget')
|
||||
self.HistoryEditLayout = QtGui.QHBoxLayout(self.HistoryEditWidget)
|
||||
self.HistoryEditLayout.setSpacing(8)
|
||||
self.HistoryEditLayout.setMargin(0)
|
||||
self.HistoryEditLayout.setObjectName(u'HistoryEditLayout')
|
||||
self.HistoryEditLabel = QtGui.QLabel(self.HistoryEditWidget)
|
||||
self.HistoryEditLabel.setObjectName(u'HistoryEditLabel')
|
||||
self.HistoryEditLayout.addWidget(self.HistoryEditLabel)
|
||||
self.HistoryEditPushButton = QtGui.QPushButton(self.HistoryEditWidget)
|
||||
self.HistoryEditPushButton.setObjectName(u'HistoryEditPushButton')
|
||||
self.HistoryEditLayout.addWidget(self.HistoryEditPushButton)
|
||||
self.HistoryEditSpacer = QtGui.QSpacerItem(147, 20,
|
||||
QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
|
||||
self.HistoryEditLayout.addItem(self.HistoryEditSpacer)
|
||||
self.FontLayout.addWidget(self.HistoryEditWidget)
|
||||
self.SlideLeftLayout.addWidget(self.FontGroupBox)
|
||||
self.SlideLeftSpacer = QtGui.QSpacerItem(20, 94,
|
||||
QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding)
|
||||
|
@ -125,7 +190,7 @@ class AlertsTab(SettingsTab):
|
|||
self.PreviewLayout.setMargin(8)
|
||||
self.PreviewLayout.setObjectName(u'PreviewLayout')
|
||||
self.FontPreview = QtGui.QLineEdit(self.PreviewGroupBox)
|
||||
self.FontPreview.setMinimumSize(QtCore.QSize(280, 100))
|
||||
self.FontPreview.setFixedSize(QtCore.QSize(350, 100))
|
||||
self.FontPreview.setReadOnly(True)
|
||||
self.FontPreview.setFocusPolicy(QtCore.Qt.NoFocus)
|
||||
self.FontPreview.setAlignment(
|
||||
|
@ -138,24 +203,40 @@ class AlertsTab(SettingsTab):
|
|||
self.SlideRightLayout.addItem(self.SlideRightSpacer)
|
||||
self.AlertsLayout.addWidget(self.AlertRightColumn)
|
||||
# Signals and slots
|
||||
QtCore.QObject.connect(self.HistoryCheckBox,
|
||||
QtCore.SIGNAL(u'stateChanged(int)'),
|
||||
self.onHistoryCheckBoxChanged)
|
||||
QtCore.QObject.connect(self.BackgroundColorButton,
|
||||
QtCore.SIGNAL(u'pressed()'), self.onBackgroundColorButtonClicked)
|
||||
QtCore.QObject.connect(self.FontColorButton,
|
||||
QtCore.SIGNAL(u'pressed()'), self.onFontColorButtonClicked)
|
||||
QtCore.QObject.connect(self.HistoryEditPushButton,
|
||||
QtCore.SIGNAL(u'pressed()'), self.onHistoryEditButtonClicked)
|
||||
QtCore.QObject.connect(self.FontComboBox,
|
||||
QtCore.SIGNAL(u'activated(int)'), self.onFontComboBoxClicked)
|
||||
QtCore.QObject.connect(self.LocationComboBox,
|
||||
QtCore.SIGNAL(u'activated(int)'), self.onLocationComboBoxClicked)
|
||||
QtCore.QObject.connect(self.TimeoutSpinBox,
|
||||
QtCore.SIGNAL(u'valueChanged(int)'), self.onTimeoutSpinBoxChanged)
|
||||
QtCore.QObject.connect(self.FontSizeSpinBox,
|
||||
QtCore.SIGNAL(u'valueChanged(int)'), self.onFontSizeSpinBoxChanged)
|
||||
|
||||
def retranslateUi(self):
|
||||
self.FontGroupBox.setTitle(self.trUtf8('Font'))
|
||||
self.FontLabel.setText(self.trUtf8('Font Name:'))
|
||||
self.FontColorLabel.setText(self.trUtf8('Font Color:'))
|
||||
self.BackgroundColorLabel.setText(self.trUtf8('Background Color:'))
|
||||
self.FontSizeLabel.setText(self.trUtf8('Font Size:'))
|
||||
self.FontSizeSpinBox.setSuffix(self.trUtf8('pt'))
|
||||
self.TimeoutLabel.setText(self.trUtf8('Alert timeout:'))
|
||||
self.TimeoutSpinBox.setSuffix(self.trUtf8('s'))
|
||||
self.LocationLabel.setText(self.trUtf8('Location:'))
|
||||
self.HistoryLabel.setText(self.trUtf8('Keep History:'))
|
||||
self.HistoryEditLabel.setText(self.trUtf8('Edit History:'))
|
||||
self.PreviewGroupBox.setTitle(self.trUtf8('Preview'))
|
||||
self.FontPreview.setText(self.trUtf8('openlp.org 2.0 rocks!'))
|
||||
self.FontPreview.setText(self.trUtf8('openlp.org'))
|
||||
self.LocationComboBox.setItemText(0, self.trUtf8('Top'))
|
||||
self.LocationComboBox.setItemText(1, self.trUtf8('Bottom'))
|
||||
|
||||
def onBackgroundColorButtonClicked(self):
|
||||
self.bg_color = QtGui.QColorDialog.getColor(
|
||||
|
@ -167,6 +248,15 @@ class AlertsTab(SettingsTab):
|
|||
def onFontComboBoxClicked(self):
|
||||
self.updateDisplay()
|
||||
|
||||
def onLocationComboBoxClicked(self, location):
|
||||
self.location = location
|
||||
|
||||
def onHistoryCheckBoxChanged(self, check_state):
|
||||
self.save_history = False
|
||||
# we have a set value convert to True/False
|
||||
if check_state == QtCore.Qt.Checked:
|
||||
self.save_history = True
|
||||
|
||||
def onFontColorButtonClicked(self):
|
||||
self.font_color = QtGui.QColorDialog.getColor(
|
||||
QtGui.QColor(self.font_color), self).name()
|
||||
|
@ -177,19 +267,33 @@ class AlertsTab(SettingsTab):
|
|||
def onTimeoutSpinBoxChanged(self):
|
||||
self.timeout = self.TimeoutSpinBox.value()
|
||||
|
||||
def onFontSizeSpinBoxChanged(self):
|
||||
self.font_size = self.FontSizeSpinBox.value()
|
||||
self.updateDisplay()
|
||||
|
||||
def onHistoryEditButtonClicked(self):
|
||||
self.parent.onAlertsEdit()
|
||||
|
||||
def load(self):
|
||||
self.timeout = int(self.config.get_config(u'timeout', 5))
|
||||
self.font_color = unicode(
|
||||
self.config.get_config(u'font color', u'#ffffff'))
|
||||
self.font_size = int(self.config.get_config(u'font size', 40))
|
||||
self.bg_color = unicode(
|
||||
self.config.get_config(u'background color', u'#660000'))
|
||||
self.font_face = unicode(
|
||||
self.config.get_config(u'font face', QtGui.QFont().family()))
|
||||
self.location = int(self.config.get_config(u'location', 0))
|
||||
self.save_history = str_to_bool(
|
||||
self.config.get_config(u'save history', u'False'))
|
||||
self.FontSizeSpinBox.setValue(self.font_size)
|
||||
self.TimeoutSpinBox.setValue(self.timeout)
|
||||
self.FontColorButton.setStyleSheet(
|
||||
u'background-color: %s' % self.font_color)
|
||||
self.BackgroundColorButton.setStyleSheet(
|
||||
u'background-color: %s' % self.bg_color)
|
||||
self.LocationComboBox.setCurrentIndex(self.location)
|
||||
self.HistoryCheckBox.setChecked(self.save_history)
|
||||
font = QtGui.QFont()
|
||||
font.setFamily(self.font_face)
|
||||
self.FontComboBox.setCurrentFont(font)
|
||||
|
@ -199,14 +303,18 @@ class AlertsTab(SettingsTab):
|
|||
self.font_face = self.FontComboBox.currentFont().family()
|
||||
self.config.set_config(u'background color', unicode(self.bg_color))
|
||||
self.config.set_config(u'font color', unicode(self.font_color))
|
||||
self.config.set_config(u'font size', unicode(self.font_size))
|
||||
self.config.set_config(u'font face', unicode(self.font_face))
|
||||
self.config.set_config(u'timeout', unicode(self.timeout))
|
||||
self.config.set_config(u'location',
|
||||
unicode(self.LocationComboBox.currentIndex()))
|
||||
self.config.set_config(u'save history', unicode(self.save_history))
|
||||
|
||||
def updateDisplay(self):
|
||||
font = QtGui.QFont()
|
||||
font.setFamily(self.FontComboBox.currentFont().family())
|
||||
font.setBold(True)
|
||||
font.setPointSize(16)
|
||||
font.setPointSize(self.font_size)
|
||||
self.FontPreview.setFont(font)
|
||||
self.FontPreview.setStyleSheet(u'background-color: %s; color: %s' % \
|
||||
(self.bg_color, self.font_color))
|
||||
(self.bg_color, self.font_color))
|
|
@ -0,0 +1,26 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
|
||||
|
||||
###############################################################################
|
||||
# OpenLP - Open Source Lyrics Projection #
|
||||
# --------------------------------------------------------------------------- #
|
||||
# Copyright (c) 2008-2010 Raoul Snyman #
|
||||
# Portions copyright (c) 2008-2010 Tim Bentley, Jonathan Corwin, Michael #
|
||||
# Gorven, Scott Guerrieri, Maikel Stuivenberg, Martin Thompson, Jon Tibble, #
|
||||
# Carsten Tinggaard #
|
||||
# --------------------------------------------------------------------------- #
|
||||
# This program is free software; you can redistribute it and/or modify it #
|
||||
# under the terms of the GNU General Public License as published by the Free #
|
||||
# Software Foundation; version 2 of the License. #
|
||||
# #
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT #
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
|
||||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
|
||||
# more details. #
|
||||
# #
|
||||
# You should have received a copy of the GNU General Public License along #
|
||||
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
|
||||
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
||||
###############################################################################
|
||||
from alertsmanager import AlertsManager
|
||||
from manager import DBManager
|
|
@ -0,0 +1,120 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
|
||||
|
||||
###############################################################################
|
||||
# OpenLP - Open Source Lyrics Projection #
|
||||
# --------------------------------------------------------------------------- #
|
||||
# Copyright (c) 2008-2010 Raoul Snyman #
|
||||
# Portions copyright (c) 2008-2010 Tim Bentley, Jonathan Corwin, Michael #
|
||||
# Gorven, Scott Guerrieri, Maikel Stuivenberg, Martin Thompson, Jon Tibble, #
|
||||
# Carsten Tinggaard #
|
||||
# --------------------------------------------------------------------------- #
|
||||
# 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
|
||||
|
||||
from PyQt4 import QtCore, QtGui
|
||||
|
||||
from openlp.core.lib import Receiver
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
class AlertsManager(QtCore.QObject):
|
||||
"""
|
||||
AlertsTab is the Alerts settings tab in the settings dialog.
|
||||
"""
|
||||
log.info(u'Alert Manager loaded')
|
||||
|
||||
def __init__(self, parent):
|
||||
QtCore.QObject.__init__(self)
|
||||
self.parent = parent
|
||||
self.timer_id = 0
|
||||
self.alertList = []
|
||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||
QtCore.SIGNAL(u'flush_alert'), self.generateAlert)
|
||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||
QtCore.SIGNAL(u'alert_text'), self.displayAlert)
|
||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||
QtCore.SIGNAL(u'screen_changed'), self.screenChanged)
|
||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||
QtCore.SIGNAL(u'config_updated'), self.screenChanged)
|
||||
|
||||
def screenChanged(self):
|
||||
log.debug(u'screen changed')
|
||||
self.screen = self.parent.maindisplay.screen
|
||||
self.alertTab = self.parent.alertsTab
|
||||
self.font = QtGui.QFont()
|
||||
self.font.setFamily(self.alertTab.font_face)
|
||||
self.font.setBold(True)
|
||||
self.font.setPointSize(self.alertTab.font_size)
|
||||
self.metrics = QtGui.QFontMetrics(self.font)
|
||||
self.alertHeight = self.metrics.height() + 4
|
||||
if self.alertTab.location == 0:
|
||||
self.alertScreenPosition = 0
|
||||
else:
|
||||
self.alertScreenPosition = self.screen[u'size'].height() - self.alertHeight
|
||||
self.alertHeight = self.screen[u'size'].height() - self.alertScreenPosition
|
||||
self.parent.maindisplay.setAlertSize(self.alertScreenPosition, self.alertHeight)
|
||||
|
||||
def displayAlert(self, text=u''):
|
||||
"""
|
||||
Called from the Alert Tab to display an alert
|
||||
|
||||
``text``
|
||||
display text
|
||||
"""
|
||||
log.debug(u'display alert called %s' % text)
|
||||
self.parent.maindisplay.parent.StatusBar.showMessage(u'')
|
||||
self.alertList.append(text)
|
||||
if self.timer_id != 0 or self.parent.maindisplay.mediaLoaded:
|
||||
self.parent.maindisplay.parent.StatusBar.showMessage(\
|
||||
self.trUtf8(u'Alert message created and delayed'))
|
||||
return
|
||||
self.generateAlert()
|
||||
|
||||
def generateAlert(self):
|
||||
log.debug(u'Generate Alert called')
|
||||
if len(self.alertList) == 0:
|
||||
return
|
||||
text = self.alertList.pop(0)
|
||||
alertTab = self.parent.alertsTab
|
||||
alertframe = \
|
||||
QtGui.QPixmap(self.screen[u'size'].width(), self.alertHeight)
|
||||
alertframe.fill(QtCore.Qt.transparent)
|
||||
painter = QtGui.QPainter(alertframe)
|
||||
painter.fillRect(alertframe.rect(), QtCore.Qt.transparent)
|
||||
painter.setRenderHint(QtGui.QPainter.Antialiasing)
|
||||
painter.fillRect(
|
||||
QtCore.QRect(
|
||||
0, 0, alertframe.rect().width(),
|
||||
alertframe.rect().height()),
|
||||
QtGui.QColor(self.alertTab.bg_color))
|
||||
painter.setFont(self.font)
|
||||
painter.setPen(QtGui.QColor(self.alertTab.font_color))
|
||||
x, y = (0, 2)
|
||||
painter.drawText(
|
||||
x, y + self.metrics.height() - self.metrics.descent() - 1, text)
|
||||
painter.end()
|
||||
self.parent.maindisplay.addAlertImage(alertframe)
|
||||
# check to see if we have a timer running
|
||||
if self.timer_id == 0:
|
||||
self.timer_id = self.startTimer(int(alertTab.timeout) * 1000)
|
||||
|
||||
def timerEvent(self, event):
|
||||
if event.timerId() == self.timer_id:
|
||||
self.parent.maindisplay.addAlertImage(None, True)
|
||||
self.killTimer(self.timer_id)
|
||||
self.timer_id = 0
|
||||
self.generateAlert()
|
|
@ -0,0 +1,46 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
|
||||
|
||||
###############################################################################
|
||||
# OpenLP - Open Source Lyrics Projection #
|
||||
# --------------------------------------------------------------------------- #
|
||||
# Copyright (c) 2008-2010 Raoul Snyman #
|
||||
# Portions copyright (c) 2008-2010 Tim Bentley, Jonathan Corwin, Michael #
|
||||
# Gorven, Scott Guerrieri, Maikel Stuivenberg, Martin Thompson, Jon Tibble, #
|
||||
# Carsten Tinggaard #
|
||||
# --------------------------------------------------------------------------- #
|
||||
# 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 #
|
||||
###############################################################################
|
||||
|
||||
class BaseModel(object):
|
||||
"""
|
||||
BaseModel provides a base object with a set of generic functions
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def populate(cls, **kwargs):
|
||||
"""
|
||||
Creates an instance of a class and populates it, returning the instance
|
||||
"""
|
||||
me = cls()
|
||||
keys = kwargs.keys()
|
||||
for key in keys:
|
||||
me.__setattr__(key, kwargs[key])
|
||||
return me
|
||||
|
||||
class AlertItem(BaseModel):
|
||||
"""
|
||||
Custom Slide model
|
||||
"""
|
||||
pass
|
|
@ -0,0 +1,107 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
|
||||
|
||||
###############################################################################
|
||||
# OpenLP - Open Source Lyrics Projection #
|
||||
# --------------------------------------------------------------------------- #
|
||||
# Copyright (c) 2008-2010 Raoul Snyman #
|
||||
# Portions copyright (c) 2008-2010 Tim Bentley, Jonathan Corwin, Michael #
|
||||
# Gorven, Scott Guerrieri, Maikel Stuivenberg, Martin Thompson, Jon Tibble, #
|
||||
# Carsten Tinggaard #
|
||||
# --------------------------------------------------------------------------- #
|
||||
# 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
|
||||
|
||||
from openlp.plugins.alerts.lib.models import init_models, metadata, AlertItem
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
class DBManager():
|
||||
"""
|
||||
The Song Manager provides a central location for all database code. This
|
||||
class takes care of connecting to the database and running all the queries.
|
||||
"""
|
||||
log.info(u'Alerts DB loaded')
|
||||
|
||||
def __init__(self, config):
|
||||
"""
|
||||
Creates the connection to the database, and creates the tables if they
|
||||
don't exist.
|
||||
"""
|
||||
self.config = config
|
||||
log.debug(u'Alerts Initialising')
|
||||
self.db_url = u''
|
||||
db_type = self.config.get_config(u'db type', u'sqlite')
|
||||
if db_type == u'sqlite':
|
||||
self.db_url = u'sqlite:///%s/alerts.sqlite' % \
|
||||
self.config.get_data_path()
|
||||
else:
|
||||
self.db_url = u'%s://%s:%s@%s/%s' % \
|
||||
(db_type, self.config.get_config(u'db username'),
|
||||
self.config.get_config(u'db password'),
|
||||
self.config.get_config(u'db hostname'),
|
||||
self.config.get_config(u'db database'))
|
||||
self.session = init_models(self.db_url)
|
||||
metadata.create_all(checkfirst=True)
|
||||
|
||||
log.debug(u'Alerts Initialised')
|
||||
|
||||
def get_all_alerts(self):
|
||||
"""
|
||||
Returns the details of a Alert Show
|
||||
"""
|
||||
return self.session.query(AlertItem).order_by(AlertItem.text).all()
|
||||
|
||||
def save_alert(self, AlertItem):
|
||||
"""
|
||||
Saves a Alert show to the database
|
||||
"""
|
||||
log.debug(u'Alert added')
|
||||
try:
|
||||
self.session.add(AlertItem)
|
||||
self.session.commit()
|
||||
log.debug(u'Alert saved')
|
||||
return True
|
||||
except:
|
||||
self.session.rollback()
|
||||
log.exception(u'Alert save failed')
|
||||
return False
|
||||
|
||||
def get_alert(self, id=None):
|
||||
"""
|
||||
Returns the details of a Alert
|
||||
"""
|
||||
if id is None:
|
||||
return AlertItem()
|
||||
else:
|
||||
return self.session.query(AlertItem).get(id)
|
||||
|
||||
def delete_alert(self, id):
|
||||
"""
|
||||
Delete a Alert show
|
||||
"""
|
||||
if id != 0:
|
||||
AlertItem = self.get_alert(id)
|
||||
try:
|
||||
self.session.delete(AlertItem)
|
||||
self.session.commit()
|
||||
return True
|
||||
except:
|
||||
self.session.rollback()
|
||||
log.exception(u'Alert deleton failed')
|
||||
return False
|
||||
else:
|
||||
return True
|
|
@ -0,0 +1,38 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
|
||||
|
||||
###############################################################################
|
||||
# OpenLP - Open Source Lyrics Projection #
|
||||
# --------------------------------------------------------------------------- #
|
||||
# Copyright (c) 2008-2010 Raoul Snyman #
|
||||
# Portions copyright (c) 2008-2010 Tim Bentley, Jonathan Corwin, Michael #
|
||||
# Gorven, Scott Guerrieri, Maikel Stuivenberg, Martin Thompson, Jon Tibble, #
|
||||
# Carsten Tinggaard #
|
||||
# --------------------------------------------------------------------------- #
|
||||
# This program is free software; you can redistribute it and/or modify it #
|
||||
# under the terms of the GNU General Public License as published by the Free #
|
||||
# Software Foundation; version 2 of the License. #
|
||||
# #
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT #
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
|
||||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
|
||||
# more details. #
|
||||
# #
|
||||
# You should have received a copy of the GNU General Public License along #
|
||||
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
|
||||
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
||||
###############################################################################
|
||||
|
||||
from sqlalchemy import MetaData
|
||||
|
||||
__all__ = ['session', 'metadata', 'engine']
|
||||
|
||||
# SQLAlchemy database engine. Updated by model.init_model()
|
||||
engine = None
|
||||
|
||||
# SQLAlchemy session manager. Updated by model.init_model()
|
||||
session = None
|
||||
|
||||
# Global metadata. If you have multiple databases with overlapping table
|
||||
# names, you'll need a metadata for each database
|
||||
metadata = MetaData()
|
|
@ -0,0 +1,39 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
|
||||
|
||||
###############################################################################
|
||||
# OpenLP - Open Source Lyrics Projection #
|
||||
# --------------------------------------------------------------------------- #
|
||||
# Copyright (c) 2008-2010 Raoul Snyman #
|
||||
# Portions copyright (c) 2008-2010 Tim Bentley, Jonathan Corwin, Michael #
|
||||
# Gorven, Scott Guerrieri, Maikel Stuivenberg, Martin Thompson, Jon Tibble, #
|
||||
# Carsten Tinggaard #
|
||||
# --------------------------------------------------------------------------- #
|
||||
# This program is free software; you can redistribute it and/or modify it #
|
||||
# under the terms of the GNU General Public License as published by the Free #
|
||||
# Software Foundation; version 2 of the License. #
|
||||
# #
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT #
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
|
||||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
|
||||
# more details. #
|
||||
# #
|
||||
# You should have received a copy of the GNU General Public License along #
|
||||
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
|
||||
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
||||
###############################################################################
|
||||
|
||||
from sqlalchemy import create_engine
|
||||
from sqlalchemy.orm import scoped_session, sessionmaker, mapper
|
||||
|
||||
from openlp.plugins.alerts.lib.meta import metadata
|
||||
from openlp.plugins.alerts.lib.tables import *
|
||||
from openlp.plugins.alerts.lib.classes import *
|
||||
|
||||
def init_models(url):
|
||||
engine = create_engine(url)
|
||||
metadata.bind = engine
|
||||
session = scoped_session(sessionmaker(autoflush=True, autocommit=False,
|
||||
bind=engine))
|
||||
mapper(AlertItem, alerts_table)
|
||||
return session
|
|
@ -0,0 +1,33 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
|
||||
|
||||
###############################################################################
|
||||
# OpenLP - Open Source Lyrics Projection #
|
||||
# --------------------------------------------------------------------------- #
|
||||
# Copyright (c) 2008-2010 Raoul Snyman #
|
||||
# Portions copyright (c) 2008-2010 Tim Bentley, Jonathan Corwin, Michael #
|
||||
# Gorven, Scott Guerrieri, Maikel Stuivenberg, Martin Thompson, Jon Tibble, #
|
||||
# Carsten Tinggaard #
|
||||
# --------------------------------------------------------------------------- #
|
||||
# This program is free software; you can redistribute it and/or modify it #
|
||||
# under the terms of the GNU General Public License as published by the Free #
|
||||
# Software Foundation; version 2 of the License. #
|
||||
# #
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT #
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
|
||||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
|
||||
# more details. #
|
||||
# #
|
||||
# You should have received a copy of the GNU General Public License along #
|
||||
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
|
||||
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
||||
###############################################################################
|
||||
|
||||
from sqlalchemy import Column, Table, types
|
||||
|
||||
from openlp.plugins.alerts.lib.meta import metadata
|
||||
|
||||
# Definition of the "alerts" table
|
||||
alerts_table = Table(u'alerts', metadata,
|
||||
Column(u'id', types.Integer(), primary_key=True),
|
||||
Column(u'text', types.UnicodeText, nullable=False))
|
|
@ -27,25 +27,26 @@ import logging
|
|||
|
||||
from PyQt4 import QtCore, QtGui
|
||||
|
||||
from openlp.core.lib import Plugin, build_icon
|
||||
from openlp.core.lib import Plugin, build_icon, PluginStatus
|
||||
from openlp.plugins.bibles.lib import BibleManager, BiblesTab, BibleMediaItem
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
class BiblePlugin(Plugin):
|
||||
global log
|
||||
log = logging.getLogger(u'BiblePlugin')
|
||||
log.info(u'Bible Plugin loaded')
|
||||
|
||||
def __init__(self, plugin_helpers):
|
||||
Plugin.__init__(self, u'Bibles', u'1.9.0', plugin_helpers)
|
||||
Plugin.__init__(self, u'Bibles', u'1.9.1', plugin_helpers)
|
||||
self.weight = -9
|
||||
self.icon = build_icon(u':/media/media_bible.png')
|
||||
#Register the bible Manager
|
||||
self.biblemanager = None
|
||||
self.status = PluginStatus.Active
|
||||
self.manager = None
|
||||
|
||||
def initialise(self):
|
||||
log.info(u'bibles Initialising')
|
||||
if self.biblemanager is None:
|
||||
self.biblemanager = BibleManager(self.config)
|
||||
if self.manager is None:
|
||||
self.manager = BibleManager(self, self.config)
|
||||
Plugin.initialise(self)
|
||||
self.insert_toolbox_item()
|
||||
self.ImportBibleItem.setVisible(True)
|
||||
|
@ -90,4 +91,10 @@ class BiblePlugin(Plugin):
|
|||
about_text = self.trUtf8('<strong>Bible Plugin</strong><br />This '
|
||||
'plugin allows bible verses from different sources to be '
|
||||
'displayed on the screen during the service.')
|
||||
return about_text
|
||||
return about_text
|
||||
|
||||
|
||||
def can_delete_theme(self, theme):
|
||||
if self.settings_tab.bible_theme == theme:
|
||||
return False
|
||||
return True
|
||||
|
|
|
@ -91,15 +91,6 @@ class Ui_BibleImportWizard(object):
|
|||
self.OsisLayout.setMargin(0)
|
||||
self.OsisLayout.setSpacing(8)
|
||||
self.OsisLayout.setObjectName(u'OsisLayout')
|
||||
self.OsisBibleNameLabel = QtGui.QLabel(self.OsisPage)
|
||||
self.OsisBibleNameLabel.setIndent(0)
|
||||
self.OsisBibleNameLabel.setObjectName(u'OsisBibleNameLabel')
|
||||
self.OsisLayout.setWidget(0, QtGui.QFormLayout.LabelRole,
|
||||
self.OsisBibleNameLabel)
|
||||
self.OsisBibleNameEdit = QtGui.QLineEdit(self.OsisPage)
|
||||
self.OsisBibleNameEdit.setObjectName(u'OsisBibleNameEdit')
|
||||
self.OsisLayout.setWidget(0, QtGui.QFormLayout.FieldRole,
|
||||
self.OsisBibleNameEdit)
|
||||
self.OsisLocationLabel = QtGui.QLabel(self.OsisPage)
|
||||
self.OsisLocationLabel.setObjectName(u'OsisLocationLabel')
|
||||
self.OsisLayout.setWidget(1, QtGui.QFormLayout.LabelRole,
|
||||
|
@ -302,13 +293,11 @@ class Ui_BibleImportWizard(object):
|
|||
self.ImportProgressLabel.setObjectName(u'ImportProgressLabel')
|
||||
self.ImportLayout.addWidget(self.ImportProgressLabel)
|
||||
self.ImportProgressBar = QtGui.QProgressBar(self.ImportPage)
|
||||
self.ImportProgressBar.setProperty(u'value', 0)
|
||||
self.ImportProgressBar.setInvertedAppearance(False)
|
||||
self.ImportProgressBar.setValue(0)
|
||||
self.ImportProgressBar.setObjectName(u'ImportProgressBar')
|
||||
self.ImportLayout.addWidget(self.ImportProgressBar)
|
||||
BibleImportWizard.addPage(self.ImportPage)
|
||||
|
||||
|
||||
self.retranslateUi(BibleImportWizard)
|
||||
self.FormatWidget.setCurrentIndex(0)
|
||||
self.WebDownloadTabWidget.setCurrentIndex(0)
|
||||
|
@ -334,7 +323,6 @@ class Ui_BibleImportWizard(object):
|
|||
self.FormatComboBox.setItemText(1, self.trUtf8('CSV'))
|
||||
self.FormatComboBox.setItemText(2, self.trUtf8('OpenSong'))
|
||||
self.FormatComboBox.setItemText(3, self.trUtf8('Web Download'))
|
||||
self.OsisBibleNameLabel.setText(self.trUtf8('Bible Name:'))
|
||||
self.OsisLocationLabel.setText(self.trUtf8('File Location:'))
|
||||
self.BooksLocationLabel.setText(self.trUtf8('Books Location:'))
|
||||
self.VerseLocationLabel.setText(self.trUtf8('Verse Location:'))
|
||||
|
@ -362,4 +350,4 @@ class Ui_BibleImportWizard(object):
|
|||
self.ImportPage.setSubTitle(
|
||||
self.trUtf8('Please wait while your Bible is imported.'))
|
||||
self.ImportProgressLabel.setText(self.trUtf8('Ready.'))
|
||||
#self.ImportProgressBar.setFormat(u'%p')
|
||||
self.ImportProgressBar.setFormat(u'%p%')
|
||||
|
|
|
@ -23,10 +23,10 @@
|
|||
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
||||
###############################################################################
|
||||
|
||||
import csv
|
||||
import logging
|
||||
import os
|
||||
import os.path
|
||||
from time import sleep
|
||||
|
||||
from PyQt4 import QtCore, QtGui
|
||||
|
||||
|
@ -34,6 +34,8 @@ from bibleimportwizard import Ui_BibleImportWizard
|
|||
from openlp.core.lib import Receiver
|
||||
from openlp.plugins.bibles.lib.manager import BibleFormat
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
class DownloadLocation(object):
|
||||
Unknown = -1
|
||||
Crosswalk = 0
|
||||
|
@ -45,8 +47,8 @@ class DownloadLocation(object):
|
|||
}
|
||||
|
||||
@classmethod
|
||||
def get_name(class_, id):
|
||||
return class_.Names[id]
|
||||
def get_name(cls, id):
|
||||
return cls.Names[id]
|
||||
|
||||
|
||||
class ImportWizardForm(QtGui.QWizard, Ui_BibleImportWizard):
|
||||
|
@ -54,12 +56,9 @@ class ImportWizardForm(QtGui.QWizard, Ui_BibleImportWizard):
|
|||
This is the Bible Import Wizard, which allows easy importing of Bibles
|
||||
into OpenLP from other formats like OSIS, CSV and OpenSong.
|
||||
"""
|
||||
|
||||
global log
|
||||
log = logging.getLogger(u'BibleImportForm')
|
||||
log.info(u'BibleImportForm loaded')
|
||||
|
||||
def __init__(self, parent, config, biblemanager, bibleplugin):
|
||||
def __init__(self, parent, config, manager, bibleplugin):
|
||||
'''
|
||||
Constructor
|
||||
'''
|
||||
|
@ -68,10 +67,10 @@ class ImportWizardForm(QtGui.QWizard, Ui_BibleImportWizard):
|
|||
self.registerFields()
|
||||
self.finishButton = self.button(QtGui.QWizard.FinishButton)
|
||||
self.cancelButton = self.button(QtGui.QWizard.CancelButton)
|
||||
self.biblemanager = biblemanager
|
||||
self.manager = manager
|
||||
self.config = config
|
||||
self.bibleplugin = bibleplugin
|
||||
self.biblemanager.set_process_dialog(self)
|
||||
self.manager.set_process_dialog(self)
|
||||
self.web_bible_list = {}
|
||||
self.loadWebBibles()
|
||||
QtCore.QObject.connect(self.LocationComboBox,
|
||||
|
@ -96,9 +95,9 @@ class ImportWizardForm(QtGui.QWizard, Ui_BibleImportWizard):
|
|||
QtCore.SIGNAL(u'currentIdChanged(int)'),
|
||||
self.onCurrentIdChanged)
|
||||
|
||||
def show(self):
|
||||
def exec_(self):
|
||||
self.setDefaults()
|
||||
return QtGui.QWizard.show()
|
||||
return QtGui.QWizard.exec_(self)
|
||||
|
||||
def validateCurrentPage(self):
|
||||
if self.currentId() == 0:
|
||||
|
@ -107,14 +106,6 @@ class ImportWizardForm(QtGui.QWizard, Ui_BibleImportWizard):
|
|||
elif self.currentId() == 1:
|
||||
# Select page
|
||||
if self.field(u'source_format').toInt()[0] == BibleFormat.OSIS:
|
||||
if self.field(u'osis_biblename').toString() == u'':
|
||||
QtGui.QMessageBox.critical(self,
|
||||
self.trUtf8('Invalid Bible Name'),
|
||||
self.trUtf8('You need to specify a name for your '
|
||||
'Bible!'),
|
||||
QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Ok))
|
||||
self.OsisBibleNameEdit.setFocus()
|
||||
return False
|
||||
if self.field(u'osis_location').toString() == u'':
|
||||
QtGui.QMessageBox.critical(self,
|
||||
self.trUtf8('Invalid Bible Location'),
|
||||
|
@ -169,6 +160,15 @@ class ImportWizardForm(QtGui.QWizard, Ui_BibleImportWizard):
|
|||
QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Ok))
|
||||
self.CopyrightEdit.setFocus()
|
||||
return False
|
||||
elif self.manager.exists(
|
||||
self.field(u'license_version').toString()):
|
||||
QtGui.QMessageBox.critical(self,
|
||||
self.trUtf8('Bible Exists'),
|
||||
self.trUtf8('This Bible already exists! Please import '
|
||||
'a different Bible or first delete the existing one.'),
|
||||
QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Ok))
|
||||
self.VersionNameEdit.setFocus()
|
||||
return False
|
||||
return True
|
||||
if self.currentId() == 3:
|
||||
# Progress page
|
||||
|
@ -209,8 +209,6 @@ class ImportWizardForm(QtGui.QWizard, Ui_BibleImportWizard):
|
|||
def registerFields(self):
|
||||
self.SelectPage.registerField(
|
||||
u'source_format', self.FormatComboBox)
|
||||
self.SelectPage.registerField(
|
||||
u'osis_biblename', self.OsisBibleNameEdit)
|
||||
self.SelectPage.registerField(
|
||||
u'osis_location', self.OSISLocationEdit)
|
||||
self.SelectPage.registerField(
|
||||
|
@ -237,24 +235,23 @@ class ImportWizardForm(QtGui.QWizard, Ui_BibleImportWizard):
|
|||
u'license_permission', self.PermissionEdit)
|
||||
|
||||
def setDefaults(self):
|
||||
self.setField(u'source_format', 0)
|
||||
self.setField(u'osis_biblename', u'')
|
||||
self.setField(u'osis_location', u'')
|
||||
self.setField(u'csv_booksfile', u'')
|
||||
self.setField(u'csv_versefile', u'')
|
||||
self.setField(u'opensong_file', u'')
|
||||
self.setField(u'web_location', 0)
|
||||
self.setField(u'web_biblename', self.BibleComboBox)
|
||||
self.setField(u'source_format', QtCore.QVariant(0))
|
||||
self.setField(u'osis_location', QtCore.QVariant(''))
|
||||
self.setField(u'csv_booksfile', QtCore.QVariant(''))
|
||||
self.setField(u'csv_versefile', QtCore.QVariant(''))
|
||||
self.setField(u'opensong_file', QtCore.QVariant(''))
|
||||
self.setField(u'web_location', QtCore.QVariant(DownloadLocation.Crosswalk))
|
||||
self.setField(u'web_biblename', QtCore.QVariant(self.BibleComboBox))
|
||||
self.setField(u'proxy_server',
|
||||
self.config.get_config(u'proxy address', u''))
|
||||
QtCore.QVariant(self.config.get_config(u'proxy address', '')))
|
||||
self.setField(u'proxy_username',
|
||||
self.config.get_config(u'proxy username',u''))
|
||||
QtCore.QVariant(self.config.get_config(u'proxy username','')))
|
||||
self.setField(u'proxy_password',
|
||||
self.config.get_config(u'proxy password',u''))
|
||||
self.setField(u'license_version', self.VersionNameEdit)
|
||||
self.setField(u'license_copyright', self.CopyrightEdit)
|
||||
self.setField(u'license_permission', self.PermissionEdit)
|
||||
self.onLocationComboBoxChanged(0)
|
||||
QtCore.QVariant(self.config.get_config(u'proxy password','')))
|
||||
self.setField(u'license_version', QtCore.QVariant(self.VersionNameEdit))
|
||||
self.setField(u'license_copyright', QtCore.QVariant(self.CopyrightEdit))
|
||||
self.setField(u'license_permission', QtCore.QVariant(self.PermissionEdit))
|
||||
self.onLocationComboBoxChanged(DownloadLocation.Crosswalk)
|
||||
|
||||
def loadWebBibles(self):
|
||||
"""
|
||||
|
@ -267,29 +264,33 @@ class ImportWizardForm(QtGui.QWizard, Ui_BibleImportWizard):
|
|||
fbibles = None
|
||||
try:
|
||||
self.web_bible_list[DownloadLocation.Crosswalk] = {}
|
||||
fbibles = open(os.path.join(filepath, u'crosswalkbooks.csv'), 'r')
|
||||
for line in fbibles:
|
||||
parts = line.split(u',')
|
||||
self.web_bible_list[DownloadLocation.Crosswalk][parts[0]] = \
|
||||
parts[1].rstrip()
|
||||
books_file = open(os.path.join(filepath, u'crosswalkbooks.csv'), 'r')
|
||||
dialect = csv.Sniffer().sniff(books_file.read(1024))
|
||||
books_file.seek(0)
|
||||
books_reader = csv.reader(books_file, dialect)
|
||||
for line in books_reader:
|
||||
self.web_bible_list[DownloadLocation.Crosswalk][line[0]] = \
|
||||
unicode(line[1], u'utf-8').strip()
|
||||
except:
|
||||
log.exception(u'Crosswalk resources missing')
|
||||
finally:
|
||||
if fbibles:
|
||||
fbibles.close()
|
||||
if books_file:
|
||||
books_file.close()
|
||||
#Load and store BibleGateway Bibles
|
||||
try:
|
||||
self.web_bible_list[DownloadLocation.BibleGateway] = {}
|
||||
fbibles = open(os.path.join(filepath, u'biblegateway.csv'), 'r')
|
||||
for line in fbibles:
|
||||
parts = line.split(u',')
|
||||
self.web_bible_list[DownloadLocation.BibleGateway][parts[0]] = \
|
||||
parts[1].rstrip()
|
||||
books_file = open(os.path.join(filepath, u'biblegateway.csv'), 'r')
|
||||
dialect = csv.Sniffer().sniff(books_file.read(1024))
|
||||
books_file.seek(0)
|
||||
books_reader = csv.reader(books_file, dialect)
|
||||
for line in books_reader:
|
||||
self.web_bible_list[DownloadLocation.BibleGateway][line[0]] = \
|
||||
unicode(line[1], u'utf-8').strip()
|
||||
except:
|
||||
log.exception(u'Biblegateway resources missing')
|
||||
finally:
|
||||
if fbibles:
|
||||
fbibles.close()
|
||||
if books_file:
|
||||
books_file.close()
|
||||
|
||||
def getFileName(self, title, editbox):
|
||||
filename = QtGui.QFileDialog.getOpenFileName(self, title,
|
||||
|
@ -317,22 +318,22 @@ class ImportWizardForm(QtGui.QWizard, Ui_BibleImportWizard):
|
|||
success = False
|
||||
if bible_type == BibleFormat.OSIS:
|
||||
# Import an OSIS bible
|
||||
success = self.biblemanager.register_osis_file_bible(
|
||||
unicode(self.field(u'license_version').toString()),
|
||||
unicode(self.field(u'osis_location').toString())
|
||||
success = self.manager.import_bible(BibleFormat.OSIS,
|
||||
name=unicode(self.field(u'license_version').toString()),
|
||||
filename=unicode(self.field(u'osis_location').toString())
|
||||
)
|
||||
elif bible_type == BibleFormat.CSV:
|
||||
# Import a CSV bible
|
||||
success = self.biblemanager.register_csv_file_bible(
|
||||
unicode(self.field(u'license_version').toString()),
|
||||
self.field(u'csv_booksfile').toString(),
|
||||
self.field(u'csv_versefile').toString()
|
||||
success = self.manager.import_bible(BibleFormat.CSV,
|
||||
name=unicode(self.field(u'license_version').toString()),
|
||||
booksfile=self.field(u'csv_booksfile').toString(),
|
||||
versefile=self.field(u'csv_versefile').toString()
|
||||
)
|
||||
elif bible_type == BibleFormat.OpenSong:
|
||||
# Import an OpenSong bible
|
||||
success = self.biblemanager.register_opensong_bible(
|
||||
unicode(self.field(u'license_version').toString()),
|
||||
self.field(u'opensong_file').toString()
|
||||
success = self.manager.import_bible(BibleFormat.OpenSong,
|
||||
name=unicode(self.field(u'license_version').toString()),
|
||||
filename=self.field(u'opensong_file').toString()
|
||||
)
|
||||
elif bible_type == BibleFormat.WebDownload:
|
||||
# Import a bible from the web
|
||||
|
@ -344,21 +345,22 @@ class ImportWizardForm(QtGui.QWizard, Ui_BibleImportWizard):
|
|||
elif download_location == DownloadLocation.BibleGateway:
|
||||
bible = self.web_bible_list[DownloadLocation.BibleGateway][
|
||||
unicode(self.BibleComboBox.currentText())]
|
||||
success = self.biblemanager.register_http_bible(
|
||||
unicode(self.field(u'license_version').toString()),
|
||||
unicode(DownloadLocation.get_name(download_location)),
|
||||
unicode(bible),
|
||||
unicode(self.field(u'proxy_server').toString()),
|
||||
unicode(self.field(u'proxy_username').toString()),
|
||||
unicode(self.field(u'proxy_password').toString())
|
||||
success = self.manager.import_bible(BibleFormat.WebDownload,
|
||||
name=unicode(self.field(u'license_version').toString()),
|
||||
download_source=unicode(DownloadLocation.get_name(download_location)),
|
||||
download_name=unicode(bible),
|
||||
proxy_server=unicode(self.field(u'proxy_server').toString()),
|
||||
proxy_username=unicode(self.field(u'proxy_username').toString()),
|
||||
proxy_password=unicode(self.field(u'proxy_password').toString())
|
||||
)
|
||||
if success:
|
||||
self.biblemanager.save_meta_data(
|
||||
self.manager.save_meta_data(
|
||||
unicode(self.field(u'license_version').toString()),
|
||||
unicode(self.field(u'license_version').toString()),
|
||||
unicode(self.field(u'license_copyright').toString()),
|
||||
unicode(self.field(u'license_permission').toString())
|
||||
)
|
||||
self.manager.reload_bibles()
|
||||
self.ImportProgressLabel.setText(self.trUtf8('Finished import.'))
|
||||
else:
|
||||
self.ImportProgressLabel.setText(
|
||||
|
|
|
@ -1,190 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
|
||||
|
||||
###############################################################################
|
||||
# OpenLP - Open Source Lyrics Projection #
|
||||
# --------------------------------------------------------------------------- #
|
||||
# Copyright (c) 2008-2010 Raoul Snyman #
|
||||
# Portions copyright (c) 2008-2010 Tim Bentley, Jonathan Corwin, Michael #
|
||||
# Gorven, Scott Guerrieri, Maikel Stuivenberg, Martin Thompson, Jon Tibble, #
|
||||
# Carsten Tinggaard #
|
||||
# --------------------------------------------------------------------------- #
|
||||
# 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 os
|
||||
import logging
|
||||
|
||||
from common import BibleCommon
|
||||
from openlp.plugins.bibles.lib.models import *
|
||||
|
||||
class BibleDBImpl(BibleCommon):
|
||||
global log
|
||||
log = logging.getLogger(u'BibleDBImpl')
|
||||
log.info(u'BibleDBimpl loaded')
|
||||
|
||||
def __init__(self, biblepath, biblename, config):
|
||||
# Connect to database
|
||||
self.config = config
|
||||
self.biblefile = os.path.join(biblepath, biblename + u'.sqlite')
|
||||
log.debug(u'Load bible %s on path %s', biblename, self.biblefile)
|
||||
db_type = self.config.get_config(u'db type', u'sqlite')
|
||||
db_url = u''
|
||||
if db_type == u'sqlite':
|
||||
db_url = u'sqlite:///' + self.biblefile
|
||||
else:
|
||||
db_url = u'%s://%s:%s@%s/%s' % \
|
||||
(db_type, self.config.get_config(u'db username'),
|
||||
self.config.get_config(u'db password'),
|
||||
self.config.get_config(u'db hostname'),
|
||||
self.config.get_config(u'db database'))
|
||||
self.metadata, self.session = init_models(db_url)
|
||||
self.metadata.create_all(checkfirst=True)
|
||||
|
||||
def create_tables(self):
|
||||
log.debug(u'createTables')
|
||||
self.save_meta(u'dbversion', u'2')
|
||||
self._load_testament(u'Old Testament')
|
||||
self._load_testament(u'New Testament')
|
||||
self._load_testament(u'Apocrypha')
|
||||
|
||||
def add_verse(self, bookid, chap, vse, text):
|
||||
verse = Verse()
|
||||
verse.book_id = bookid
|
||||
verse.chapter = chap
|
||||
verse.verse = vse
|
||||
verse.text = text
|
||||
self.session.add(verse)
|
||||
return verse
|
||||
|
||||
def save_verses(self):
|
||||
log.debug('Saving verses...')
|
||||
self.session.commit()
|
||||
|
||||
def create_chapter(self, bookid, chap, textlist):
|
||||
log.debug(u'create_chapter %s,%s', bookid, chap)
|
||||
#text list has book and chapter as first to elements of the array
|
||||
for verse_number, verse_text in textlist.iteritems():
|
||||
verse = Verse()
|
||||
verse.book_id = bookid
|
||||
verse.chapter = chap
|
||||
verse.verse = verse_number
|
||||
verse.text = verse_text
|
||||
self.session.add(verse)
|
||||
self.session.commit()
|
||||
|
||||
def create_book(self, bookname, bookabbrev, testament=1):
|
||||
log.debug(u'create_book %s,%s', bookname, bookabbrev)
|
||||
book = Book()
|
||||
book.testament_id = testament
|
||||
book.name = bookname
|
||||
book.abbreviation = bookabbrev
|
||||
self.session.add(book)
|
||||
self.session.commit()
|
||||
return book
|
||||
|
||||
def save_meta(self, key, value):
|
||||
log.debug(u'save_meta %s/%s', key, value)
|
||||
bmeta = BibleMeta()
|
||||
bmeta.key = key
|
||||
bmeta.value = value
|
||||
self.session.add(bmeta)
|
||||
self.session.commit()
|
||||
|
||||
def get_meta(self, metakey):
|
||||
log.debug(u'get meta %s', metakey)
|
||||
return self.session.query(BibleMeta).filter_by(key=metakey).first()
|
||||
|
||||
def delete_meta(self, metakey):
|
||||
biblemeta = self.get_meta(metakey)
|
||||
try:
|
||||
self.session.delete(biblemeta)
|
||||
self.session.commit()
|
||||
return True
|
||||
except:
|
||||
return False
|
||||
|
||||
def _load_testament(self, testament):
|
||||
log.debug(u'load_testaments %s', testament)
|
||||
test = ONTestament()
|
||||
test.name = testament
|
||||
self.session.add(test)
|
||||
self.session.commit()
|
||||
|
||||
def get_bible_books(self):
|
||||
log.debug(u'get_bible_books')
|
||||
return self.session.query(Book).order_by(Book.id).all()
|
||||
|
||||
def get_max_bible_book_verses(self, bookname, chapter):
|
||||
log.debug(u'get_max_bible_book_verses %s, %s', bookname, chapter)
|
||||
verse = self.session.query(Verse).join(Book).filter(
|
||||
Book.name == bookname).filter(
|
||||
Verse.chapter == chapter).order_by(Verse.verse.desc()).first()
|
||||
if verse == None:
|
||||
return 0
|
||||
else:
|
||||
return verse.verse
|
||||
|
||||
def get_max_bible_book_chapter(self, bookname):
|
||||
log.debug(u'get_max_bible_book_chapter %s', bookname)
|
||||
verse = self.session.query(Verse).join(Book).filter(
|
||||
Book.name == bookname).order_by(Verse.chapter.desc()).first()
|
||||
if verse == None:
|
||||
return 0
|
||||
else:
|
||||
return verse.chapter
|
||||
|
||||
def get_bible_book(self, bookname):
|
||||
log.debug(u'get_bible_book %s', bookname)
|
||||
book = self.session.query(Book).filter(
|
||||
Book.name.like(bookname + u'%')).first()
|
||||
if book is None:
|
||||
book = self.session.query(Book).filter(
|
||||
Book.abbreviation.like(bookname + u'%')).first()
|
||||
return book
|
||||
|
||||
def get_bible_chapter(self, id, chapter):
|
||||
log.debug(u'get_bible_chapter %s, %s', id, chapter)
|
||||
return self.session.query(Verse).filter_by(chapter=chapter).filter_by(
|
||||
book_id=id).first()
|
||||
|
||||
def get_bible_text(self, bookname, chapter, sverse, everse):
|
||||
log.debug(u'get_bible_text %s, %s, %s, %s', bookname, chapter, sverse,
|
||||
everse)
|
||||
#Look up book name or abbreviation
|
||||
book = self.get_bible_book(bookname)
|
||||
if book:
|
||||
bookname = book.name
|
||||
log.debug(u'bookname corrected to %s' % bookname)
|
||||
verses = self.session.query(Verse).join(Book).filter(
|
||||
Book.name == bookname).filter(Verse.chapter == chapter).filter(
|
||||
Verse.verse>=sverse).filter(Verse.verse<=everse).order_by(
|
||||
Verse.verse).all()
|
||||
return verses
|
||||
|
||||
def get_verses_from_text(self, versetext):
|
||||
log.debug(u'get_verses_from_text %s',versetext)
|
||||
versetext = u'%%%s%%' % versetext
|
||||
verses = self.session.query(Verse).filter(
|
||||
Verse.text.like(versetext)).all()
|
||||
return verses
|
||||
|
||||
def dump_bible(self):
|
||||
log.debug( u'.........Dumping Bible Database')
|
||||
log.debug( '...............................Books ')
|
||||
books = self.session.query(Book).all()
|
||||
log.debug(books)
|
||||
log.debug( u'...............................Verses ')
|
||||
verses = self.session.query(Verse).all()
|
||||
log.debug(verses)
|
|
@ -1,228 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
|
||||
|
||||
###############################################################################
|
||||
# OpenLP - Open Source Lyrics Projection #
|
||||
# --------------------------------------------------------------------------- #
|
||||
# Copyright (c) 2008-2010 Raoul Snyman #
|
||||
# Portions copyright (c) 2008-2010 Tim Bentley, Jonathan Corwin, Michael #
|
||||
# Gorven, Scott Guerrieri, Maikel Stuivenberg, Martin Thompson, Jon Tibble, #
|
||||
# Carsten Tinggaard #
|
||||
# --------------------------------------------------------------------------- #
|
||||
# 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
|
||||
|
||||
from common import BibleCommon, SearchResults
|
||||
|
||||
class BGExtract(BibleCommon):
|
||||
global log
|
||||
log = logging.getLogger(u'BibleHTTPMgr(BG_extract)')
|
||||
log.info(u'BG_extract loaded')
|
||||
|
||||
def __init__(self, proxyurl= None):
|
||||
log.debug(u'init %s', proxyurl)
|
||||
self.proxyurl = proxyurl
|
||||
|
||||
def get_bible_chapter(self, version, bookname, chapter) :
|
||||
"""
|
||||
Access and decode bibles via the BibleGateway website
|
||||
|
||||
``Version``
|
||||
The version of the bible like 31 for New International version
|
||||
|
||||
``bookname``
|
||||
Name of the Book
|
||||
|
||||
``chapter``
|
||||
Chapter number
|
||||
"""
|
||||
log.debug(u'get_bible_chapter %s,%s,%s',
|
||||
version, bookname, chapter)
|
||||
urlstring = \
|
||||
u'http://www.biblegateway.com/passage/?search=%s+%d&version=%s' % \
|
||||
(bookname, chapter, version)
|
||||
log.debug(u'BibleGateway urm = %s' % urlstring)
|
||||
xml_string = self._get_web_text(urlstring, self.proxyurl)
|
||||
verseSearch = u'<sup class=\"versenum'
|
||||
verseFootnote = u'<sup class=\'footnote'
|
||||
verse = 1
|
||||
i = xml_string.find(u'result-text-style-normal') + 26
|
||||
xml_string = xml_string[i:len(xml_string)]
|
||||
versePos = xml_string.find(verseSearch)
|
||||
bible = {}
|
||||
while versePos > -1:
|
||||
# clear out string
|
||||
verseText = u''
|
||||
versePos = xml_string.find(u'</sup>', versePos) + 6
|
||||
i = xml_string.find(verseSearch, versePos + 1)
|
||||
# Not sure if this is needed now
|
||||
if i == -1:
|
||||
i = xml_string.find(u'</div', versePos + 1)
|
||||
j = xml_string.find(u'<strong', versePos + 1)
|
||||
if j > 0 and j < i:
|
||||
i = j
|
||||
verseText = xml_string[versePos + 7 : i ]
|
||||
# store the verse
|
||||
bible[verse] = self._clean_text(verseText)
|
||||
versePos = -1
|
||||
else:
|
||||
verseText = xml_string[versePos: i]
|
||||
start_tag = verseText.find(verseFootnote)
|
||||
while start_tag > -1:
|
||||
end_tag = verseText.find(u'</sup>')
|
||||
verseText = verseText[:start_tag] + verseText[end_tag + 6:len(verseText)]
|
||||
start_tag = verseText.find(verseFootnote)
|
||||
# Chop off verse and start again
|
||||
xml_string = xml_string[i:]
|
||||
#look for the next verse
|
||||
versePos = xml_string.find(verseSearch)
|
||||
# store the verse
|
||||
bible[verse] = self._clean_text(verseText)
|
||||
verse += 1
|
||||
return SearchResults(bookname, chapter, bible)
|
||||
|
||||
class CWExtract(BibleCommon):
|
||||
global log
|
||||
log = logging.getLogger(u'BibleHTTPMgr(CWExtract)')
|
||||
log.info(u'CWExtract loaded')
|
||||
|
||||
def __init__(self, proxyurl=None):
|
||||
log.debug(u'init %s', proxyurl)
|
||||
self.proxyurl = proxyurl
|
||||
|
||||
def get_bible_chapter(self, version, bookname, chapter) :
|
||||
log.debug(u'getBibleChapter %s,%s,%s',
|
||||
version,bookname, chapter)
|
||||
"""
|
||||
Access and decode bibles via the Crosswalk website
|
||||
|
||||
``version``
|
||||
The version of the bible like niv for New International Version
|
||||
|
||||
``bookname``
|
||||
Text name of in english e.g. 'gen' for Genesis
|
||||
|
||||
``chapter``
|
||||
Chapter number
|
||||
"""
|
||||
log.debug(u'get_bible_chapter %s,%s,%s',
|
||||
version, bookname, chapter)
|
||||
bookname = bookname.replace(u' ', u'')
|
||||
urlstring = u'http://bible.crosswalk.com/OnlineStudyBible/bible.cgi?word=%s+%d&version=%s'\
|
||||
% (bookname, chapter, version)
|
||||
xml_string = self._get_web_text(urlstring, self.proxyurl)
|
||||
## Strip Book Title from Heading to return it to system
|
||||
##
|
||||
i = xml_string.find(u'<title>')
|
||||
j = xml_string.find(u'-', i)
|
||||
book_title = xml_string[i + 7:j]
|
||||
book_title = book_title.rstrip()
|
||||
log.debug(u'Book Title %s', book_title)
|
||||
i = book_title.rfind(u' ')
|
||||
book_chapter = book_title[i+1:len(book_title)].rstrip()
|
||||
book_title = book_title[:i].rstrip()
|
||||
log.debug(u'Book Title %s', book_title)
|
||||
log.debug(u'Book Chapter %s', book_chapter)
|
||||
# Strip Verse Data from Page and build an array
|
||||
|
||||
i = xml_string.find(u'NavCurrentChapter')
|
||||
xml_string = xml_string[i:len(xml_string)]
|
||||
i = xml_string.find(u'<TABLE')
|
||||
xml_string = xml_string[i:len(xml_string)]
|
||||
i = xml_string.find(u'<B>')
|
||||
#remove the <B> at the front
|
||||
xml_string = xml_string[i + 3 :len(xml_string)]
|
||||
# Remove the heading for the book
|
||||
i = xml_string.find(u'<B>')
|
||||
#remove the <B> at the front
|
||||
xml_string = xml_string[i + 3 :len(xml_string)]
|
||||
versePos = xml_string.find(u'<BLOCKQUOTE>')
|
||||
bible = {}
|
||||
while versePos > 0:
|
||||
verseText = u''
|
||||
versePos = xml_string.find(u'<B><I>', versePos) + 6
|
||||
i = xml_string.find(u'</I></B>', versePos)
|
||||
# Got the Chapter
|
||||
verse = xml_string[versePos:i]
|
||||
# move the starting position to begining of the text
|
||||
versePos = i + 8
|
||||
# find the start of the next verse
|
||||
i = xml_string.find(u'<B><I>', versePos)
|
||||
if i == -1:
|
||||
i = xml_string.find(u'</BLOCKQUOTE>',versePos)
|
||||
verseText = xml_string[versePos: i]
|
||||
versePos = 0
|
||||
else:
|
||||
verseText = xml_string[versePos: i]
|
||||
versePos = i
|
||||
bible[verse] = self._clean_text(verseText)
|
||||
return SearchResults(book_title, book_chapter, bible)
|
||||
|
||||
class BibleHTTPImpl():
|
||||
global log
|
||||
log = logging.getLogger(u'BibleHTTPMgr')
|
||||
log.info(u'BibleHTTP manager loaded')
|
||||
def __init__(self):
|
||||
"""
|
||||
Finds all the bibles defined for the system
|
||||
Creates an Interface Object for each bible containing connection
|
||||
information
|
||||
|
||||
Throws Exception if no Bibles are found.
|
||||
|
||||
Init confirms the bible exists and stores the database path.
|
||||
"""
|
||||
self.biblesource = u''
|
||||
self.proxyurl = None
|
||||
self.bibleid = None
|
||||
|
||||
def set_proxy(self, proxyurl):
|
||||
"""
|
||||
Set the Proxy Url
|
||||
"""
|
||||
log.debug(u'set_proxy %s', proxyurl)
|
||||
self.proxyurl = proxyurl
|
||||
|
||||
def set_bibleid(self, bibleid):
|
||||
"""
|
||||
Set the bible id.
|
||||
The shore identifier of the the bible.
|
||||
"""
|
||||
log.debug(u'set_bibleid %s', bibleid)
|
||||
self.bibleid = bibleid
|
||||
|
||||
def set_bible_source(self, biblesource):
|
||||
"""
|
||||
Set the source of where the bible text is coming from
|
||||
"""
|
||||
log.debug(u'set_bible_source %s', biblesource)
|
||||
self.biblesource = biblesource
|
||||
|
||||
def get_bible_chapter(self, version, bookname, chapter):
|
||||
"""
|
||||
Receive the request and call the relevant handler methods
|
||||
"""
|
||||
log.debug(u'get_bible_chapter %s,%s,%s',
|
||||
version, bookname, chapter)
|
||||
log.debug(u'biblesource = %s', self.biblesource)
|
||||
try:
|
||||
if self.biblesource.lower() == u'crosswalk':
|
||||
ev = CWExtract(self.proxyurl)
|
||||
else:
|
||||
ev = BGExtract(self.proxyurl)
|
||||
return ev.get_bible_chapter(self.bibleid, bookname, chapter)
|
||||
except:
|
||||
log.exception("Failed to get bible chapter")
|
|
@ -27,15 +27,14 @@ import logging
|
|||
|
||||
from PyQt4 import QtCore, QtGui
|
||||
|
||||
from openlp.core.lib import str_to_bool, Receiver
|
||||
from openlp.core.lib import SettingsTab
|
||||
from openlp.core.lib import str_to_bool, Receiver, SettingsTab
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
class BiblesTab(SettingsTab):
|
||||
"""
|
||||
BiblesTab is the Bibles settings tab in the settings dialog.
|
||||
"""
|
||||
global log
|
||||
log = logging.getLogger(u'BibleTab')
|
||||
log.info(u'Bible Tab loaded')
|
||||
|
||||
def __init__(self, title, section=None):
|
||||
|
@ -226,4 +225,4 @@ class BiblesTab(SettingsTab):
|
|||
# Not Found
|
||||
id = 0
|
||||
self.bible_theme = u''
|
||||
self.BibleThemeComboBox.setCurrentIndex(id)
|
||||
self.BibleThemeComboBox.setCurrentIndex(id)
|
||||
|
|
|
@ -24,10 +24,99 @@
|
|||
###############################################################################
|
||||
|
||||
import urllib2
|
||||
import chardet
|
||||
import logging
|
||||
import re
|
||||
import chardet
|
||||
|
||||
class SearchResults:
|
||||
only_verses = re.compile(r'([\w .]+)[ ]+([0-9]+)[ ]*[:|v|V][ ]*([0-9]+)'
|
||||
r'(?:[ ]*-[ ]*([0-9]+|end))?(?:[ ]*,[ ]*([0-9]+)(?:[ ]*-[ ]*([0-9]+|end))?)?',
|
||||
re.UNICODE)
|
||||
chapter_range = re.compile(r'([\w .]+)[ ]+([0-9]+)[ ]*[:|v|V][ ]*'
|
||||
r'([0-9]+)[ ]*-[ ]*([0-9]+)[ ]*[:|v|V][ ]*([0-9]+)',
|
||||
re.UNICODE)
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
def parse_reference(reference):
|
||||
"""
|
||||
This is the über-awesome function that takes a person's typed in string
|
||||
and converts it to a reference list, a list of references to be queried
|
||||
from the Bible database files.
|
||||
|
||||
The reference list is a list of tuples, with each tuple structured like
|
||||
this::
|
||||
|
||||
(book, chapter, start_verse, end_verse)
|
||||
"""
|
||||
reference = reference.strip()
|
||||
log.debug('parse_reference("%s")', reference)
|
||||
reference_list = []
|
||||
# We start with the most "complicated" match first, so that they are found
|
||||
# first, and we don't have any "false positives".
|
||||
match = chapter_range.match(reference)
|
||||
if match:
|
||||
log.debug('Found a chapter range.')
|
||||
book = match.group(1)
|
||||
from_verse = match.group(3)
|
||||
to_verse = match.group(5)
|
||||
if int(match.group(2)) == int(match.group(4)):
|
||||
reference_list.append(
|
||||
(match.group(1), int(match.group(2)), from_verse, to_verse)
|
||||
)
|
||||
else:
|
||||
if int(match.group(2)) > int(match.group(4)):
|
||||
from_chapter = int(match.group(4))
|
||||
to_chapter = int(match.group(2))
|
||||
else:
|
||||
from_chapter = int(match.group(2))
|
||||
to_chapter = int(match.group(4))
|
||||
for chapter in xrange(from_chapter, to_chapter + 1):
|
||||
if chapter == from_chapter:
|
||||
reference_list.append(
|
||||
(match.group(1), chapter, from_verse, -1)
|
||||
)
|
||||
elif chapter == to_chapter:
|
||||
reference_list.append(
|
||||
(match.group(1), chapter, 1, to_verse)
|
||||
)
|
||||
else:
|
||||
reference_list.append(
|
||||
(match.group(1), chapter, 1, -1)
|
||||
)
|
||||
else:
|
||||
match = only_verses.match(reference)
|
||||
if match:
|
||||
log.debug('Found a verse range.')
|
||||
book = match.group(1)
|
||||
chapter = match.group(2)
|
||||
verse = match.group(3)
|
||||
if match.group(4) is None:
|
||||
reference_list.append((book, chapter, verse, verse))
|
||||
elif match.group(5) is None:
|
||||
end_verse = match.group(4)
|
||||
if end_verse == u'end':
|
||||
end_verse = -1
|
||||
reference_list.append((book, chapter, verse, end_verse))
|
||||
elif match.group(6) is None:
|
||||
reference_list.extend([
|
||||
(book, chapter, verse, match.group(4)),
|
||||
(book, chapter, match.group(5), match.group(5))
|
||||
])
|
||||
else:
|
||||
end_verse = match.group(6)
|
||||
if end_verse == u'end':
|
||||
end_verse = -1
|
||||
reference_list.extend([
|
||||
(book, chapter, verse, match.group(4)),
|
||||
(book, chapter, match.group(5), end_verse)
|
||||
])
|
||||
else:
|
||||
log.debug('Didn\'t find anything.')
|
||||
log.debug(reference_list)
|
||||
return reference_list
|
||||
|
||||
|
||||
class SearchResults(object):
|
||||
"""
|
||||
Encapsulate a set of search results. This is Bible-type independant.
|
||||
"""
|
||||
|
@ -77,16 +166,8 @@ class BibleCommon(object):
|
|||
"""
|
||||
A common ancestor for bible download sites.
|
||||
"""
|
||||
global log
|
||||
log = logging.getLogger(u'BibleCommon')
|
||||
log.info(u'BibleCommon')
|
||||
|
||||
def __init__(self):
|
||||
"""
|
||||
An empty constructor... not sure why I'm here.
|
||||
"""
|
||||
pass
|
||||
|
||||
def _get_web_text(self, urlstring, proxyurl):
|
||||
"""
|
||||
Get the HTML from the web page.
|
||||
|
@ -165,4 +246,4 @@ class BibleCommon(object):
|
|||
text = text[:start_tag] + text[end_tag + 1:]
|
||||
start_tag = text.find(u'<')
|
||||
text = text.replace(u'>', u'')
|
||||
return text.rstrip().lstrip()
|
||||
return text.rstrip().lstrip()
|
||||
|
|
|
@ -25,96 +25,97 @@
|
|||
|
||||
import logging
|
||||
import chardet
|
||||
import csv
|
||||
|
||||
from openlp.plugins.bibles.lib.common import BibleCommon
|
||||
from openlp.core.lib import Receiver
|
||||
from db import BibleDB
|
||||
|
||||
class BibleCSVImpl(BibleCommon):
|
||||
global log
|
||||
log = logging.getLogger(u'BibleCSVImpl')
|
||||
log.info(u'BibleCVSImpl loaded')
|
||||
def __init__(self, bibledb):
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
class CSVBible(BibleDB):
|
||||
"""
|
||||
This class provides a specialisation for importing of CSV Bibles.
|
||||
"""
|
||||
|
||||
def __init__(self, parent, **kwargs):
|
||||
"""
|
||||
Loads a Bible from a pair of CVS files passed in
|
||||
This class assumes the files contain all the information and
|
||||
a clean bible is being loaded.
|
||||
"""
|
||||
self.bibledb = bibledb
|
||||
self.loadbible = True
|
||||
BibleDB.__init__(self, parent, **kwargs)
|
||||
log.info(self.__class__.__name__)
|
||||
if u'booksfile' not in kwargs:
|
||||
raise KeyError(u'You have to supply a file to import books from.')
|
||||
self.booksfile = kwargs[u'booksfile']
|
||||
if u'versesfile' not in kwargs:
|
||||
raise KeyError(u'You have to supply a file to import verses from.')
|
||||
self.versesfile = kwargs[u'versesfile']
|
||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||
QtCore.SIGNAL(u'openlpstopimport'), self.stop_import)
|
||||
|
||||
def stop_import(self):
|
||||
self.loadbible = False
|
||||
"""
|
||||
Stops the import of the Bible.
|
||||
"""
|
||||
log.debug('Stopping import!')
|
||||
self.stop_import_flag = True
|
||||
|
||||
def load_data(self, booksfile, versesfile, dialogobject):
|
||||
def do_import(self):
|
||||
#Populate the Tables
|
||||
success = True
|
||||
fbooks = None
|
||||
books_file = None
|
||||
try:
|
||||
fbooks = open(booksfile, 'r')
|
||||
count = 0
|
||||
for line in fbooks:
|
||||
books_file = open(self.booksfile, 'r')
|
||||
dialect = csv.Sniffer().sniff(books_file.read(1024))
|
||||
books_file.seek(0)
|
||||
books_reader = csv.reader(books_file, dialect)
|
||||
for line in books_reader:
|
||||
# cancel pressed
|
||||
if not self.loadbible:
|
||||
if self.stop_import_flag:
|
||||
break
|
||||
details = chardet.detect(line)
|
||||
line = unicode(line, details['encoding'])
|
||||
p = line.split(u',')
|
||||
p1 = p[1].replace(u'"', u'')
|
||||
p2 = p[2].replace(u'"', u'')
|
||||
p3 = p[3].replace(u'"', u'')
|
||||
self.bibledb.create_book(p2, p3, int(p1))
|
||||
count += 1
|
||||
#Flush the screen events
|
||||
if count % 3 == 0:
|
||||
Receiver.send_message(u'process_events')
|
||||
count = 0
|
||||
details = chardet.detect(line[1])
|
||||
self.create_book(unicode(line[1], details['encoding']),
|
||||
line[2], int(line[0]))
|
||||
Receiver.send_message(u'process_events')
|
||||
except:
|
||||
log.exception(u'Loading books from file failed')
|
||||
success = False
|
||||
finally:
|
||||
if fbooks:
|
||||
fbooks.close()
|
||||
if books_file:
|
||||
books_file.close()
|
||||
if not success:
|
||||
return False
|
||||
fverse = None
|
||||
verse_file = None
|
||||
try:
|
||||
fverse = open(versesfile, 'r')
|
||||
count = 0
|
||||
book_ptr = None
|
||||
for line in fverse:
|
||||
if not self.loadbible: # cancel pressed
|
||||
verse_file = open(versesfile, 'r')
|
||||
dialect = csv.Sniffer().sniff(verse_file.read(1024))
|
||||
verse_file.seek(0)
|
||||
verse_reader = csv.reader(verse_file, dialect)
|
||||
for line in verse_reader:
|
||||
if self.stop_import_flag: # cancel pressed
|
||||
break
|
||||
details = chardet.detect(line)
|
||||
line = unicode(line, details['encoding'])
|
||||
# split into 3 units and leave the rest as a single field
|
||||
p = line.split(u',', 3)
|
||||
p0 = p[0].replace(u'"', u'')
|
||||
p3 = p[3].replace(u'"', u'')
|
||||
if book_ptr is not p0:
|
||||
book = self.bibledb.get_bible_book(p0)
|
||||
details = chardet.detect(line[3])
|
||||
if book_ptr != line[0]:
|
||||
book = self.get_book(line[0])
|
||||
book_ptr = book.name
|
||||
# increament the progress bar
|
||||
dialogobject.incrementProgressBar(u'Importing %s %s' % \
|
||||
book.name)
|
||||
self.bibledb.add_verse(book.id, p[1], p[2], p3)
|
||||
count += 1
|
||||
#Every x verses repaint the screen
|
||||
if count % 3 == 0:
|
||||
Receiver.send_message(u'process_events')
|
||||
count = 0
|
||||
self.bibledb.save_verses()
|
||||
self.wizard.incrementProgressBar(
|
||||
u'Importing %s %s' % (book.name, line[1]))
|
||||
self.commit()
|
||||
self.create_verse(book.id, line[1], line[2],
|
||||
unicode(line[3], details['encoding']))
|
||||
Receiver.send_message(u'process_events')
|
||||
self.commit()
|
||||
except:
|
||||
log.exception(u'Loading verses from file failed')
|
||||
success = False
|
||||
finally:
|
||||
if fverse:
|
||||
fverse.close()
|
||||
if not self.loadbible:
|
||||
dialogobject.incrementProgressBar(u'Import canceled!')
|
||||
dialogobject.ImportProgressBar.setValue(
|
||||
dialogobject.ImportProgressBar.maximum())
|
||||
if verse_file:
|
||||
verse_file.close()
|
||||
if self.stop_import_flag:
|
||||
self.wizard.incrementProgressBar(u'Import canceled!')
|
||||
return False
|
||||
else:
|
||||
return success
|
||||
return success
|
||||
|
|
@ -0,0 +1,286 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
|
||||
|
||||
###############################################################################
|
||||
# OpenLP - Open Source Lyrics Projection #
|
||||
# --------------------------------------------------------------------------- #
|
||||
# Copyright (c) 2008-2010 Raoul Snyman #
|
||||
# Portions copyright (c) 2008-2010 Tim Bentley, Jonathan Corwin, Michael #
|
||||
# Gorven, Scott Guerrieri, Maikel Stuivenberg, Martin Thompson, Jon Tibble, #
|
||||
# Carsten Tinggaard #
|
||||
# --------------------------------------------------------------------------- #
|
||||
# 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 os
|
||||
import logging
|
||||
import chardet
|
||||
|
||||
from sqlalchemy import or_
|
||||
from PyQt4 import QtCore
|
||||
|
||||
from openlp.plugins.bibles.lib.models import *
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
class BibleDB(QtCore.QObject):
|
||||
"""
|
||||
This class represents a database-bound Bible. It is used as a base class
|
||||
for all the custom importers, so that the can implement their own import
|
||||
methods, but benefit from the database methods in here via inheritance,
|
||||
rather than depending on yet another object.
|
||||
"""
|
||||
|
||||
def __init__(self, parent, **kwargs):
|
||||
"""
|
||||
The constructor loads up the database and creates and initialises the
|
||||
tables if the database doesn't exist.
|
||||
|
||||
**Required keyword arguments:**
|
||||
|
||||
``path``
|
||||
The path to the bible database file.
|
||||
|
||||
``name``
|
||||
The name of the database. This is also used as the file name for
|
||||
SQLite databases.
|
||||
|
||||
``config``
|
||||
The configuration object, passed in from the plugin.
|
||||
"""
|
||||
log.info(u'BibleDB loaded')
|
||||
QtCore.QObject.__init__(self)
|
||||
if u'path' not in kwargs:
|
||||
raise KeyError(u'Missing keyword argument "path".')
|
||||
if u'name' not in kwargs:
|
||||
raise KeyError(u'Missing keyword argument "name".')
|
||||
if u'config' not in kwargs:
|
||||
raise KeyError(u'Missing keyword argument "config".')
|
||||
self.stop_import_flag = False
|
||||
self.name = kwargs[u'name']
|
||||
self.config = kwargs[u'config']
|
||||
self.db_file = os.path.join(kwargs[u'path'],
|
||||
u'%s.sqlite' % kwargs[u'name'])
|
||||
log.debug(u'Load bible %s on path %s', kwargs[u'name'], self.db_file)
|
||||
db_type = self.config.get_config(u'db type', u'sqlite')
|
||||
db_url = u''
|
||||
if db_type == u'sqlite':
|
||||
db_url = u'sqlite:///' + self.db_file
|
||||
else:
|
||||
db_url = u'%s://%s:%s@%s/%s' % \
|
||||
(db_type, self.config.get_config(u'db username'),
|
||||
self.config.get_config(u'db password'),
|
||||
self.config.get_config(u'db hostname'),
|
||||
self.config.get_config(u'db database'))
|
||||
self.metadata, self.session = init_models(db_url)
|
||||
self.metadata.create_all(checkfirst=True)
|
||||
|
||||
def register(self, wizard):
|
||||
"""
|
||||
This method basically just initialialises the database. It is called
|
||||
from the Bible Manager when a Bible is imported. Descendant classes
|
||||
may want to override this method to supply their own custom
|
||||
initialisation as well.
|
||||
"""
|
||||
self.wizard = wizard
|
||||
self.create_tables()
|
||||
return self.name
|
||||
|
||||
def commit(self):
|
||||
log.debug('Committing...')
|
||||
self.session.commit()
|
||||
|
||||
def create_tables(self):
|
||||
log.debug(u'createTables')
|
||||
self.create_meta(u'dbversion', u'2')
|
||||
self.create_testament(u'Old Testament')
|
||||
self.create_testament(u'New Testament')
|
||||
self.create_testament(u'Apocrypha')
|
||||
|
||||
def create_testament(self, testament):
|
||||
log.debug(u'BibleDB.create_testament("%s")', testament)
|
||||
self.session.add(Testament.populate(name=testament))
|
||||
self.commit()
|
||||
|
||||
def create_book(self, name, abbrev, testament=1):
|
||||
log.debug(u'create_book %s,%s', name, abbrev)
|
||||
book = Book.populate(name=name, abbreviation=abbrev,
|
||||
testament_id=testament)
|
||||
self.session.add(book)
|
||||
self.commit()
|
||||
return book
|
||||
|
||||
def create_chapter(self, book_id, chapter, textlist):
|
||||
log.debug(u'create_chapter %s,%s', book_id, chapter)
|
||||
#text list has book and chapter as first two elements of the array
|
||||
for verse_number, verse_text in textlist.iteritems():
|
||||
verse = Verse.populate(
|
||||
book_id = book_id,
|
||||
chapter = chapter,
|
||||
verse = verse_number,
|
||||
text = verse_text
|
||||
)
|
||||
self.session.add(verse)
|
||||
self.commit()
|
||||
|
||||
def create_verse(self, book_id, chapter, verse, text):
|
||||
if not isinstance(text, unicode):
|
||||
details = chardet.detect(text)
|
||||
text = unicode(text, details[u'encoding'])
|
||||
verse = Verse.populate(
|
||||
book_id=book_id,
|
||||
chapter=chapter,
|
||||
verse=verse,
|
||||
text=text
|
||||
)
|
||||
self.session.add(verse)
|
||||
return verse
|
||||
|
||||
def create_meta(self, key, value):
|
||||
log.debug(u'save_meta %s/%s', key, value)
|
||||
self.session.add(BibleMeta.populate(key=key, value=value))
|
||||
self.commit()
|
||||
|
||||
def get_books(self):
|
||||
log.debug(u'BibleDB.get_books()')
|
||||
return self.session.query(Book).order_by(Book.id).all()
|
||||
|
||||
def get_book(self, book):
|
||||
log.debug(u'BibleDb.get_book("%s")', book)
|
||||
db_book = self.session.query(Book)\
|
||||
.filter(Book.name.like(book + u'%'))\
|
||||
.first()
|
||||
if db_book is None:
|
||||
db_book = self.session.query(Book)\
|
||||
.filter(Book.abbreviation.like(book + u'%'))\
|
||||
.first()
|
||||
return db_book
|
||||
|
||||
def get_chapter(self, id, chapter):
|
||||
log.debug(u'BibleDB.get_chapter("%s", %s)', id, chapter)
|
||||
return self.session.query(Verse)\
|
||||
.filter_by(chapter=chapter)\
|
||||
.filter_by(book_id=id)\
|
||||
.first()
|
||||
|
||||
def get_verses(self, reference_list):
|
||||
"""
|
||||
This is probably the most used function. It retrieves the list of
|
||||
verses based on the user's query.
|
||||
|
||||
``reference_list``
|
||||
This is the list of references the media manager item wants. It is
|
||||
a list of tuples, with the following format::
|
||||
|
||||
(book, chapter, start_verse, end_verse)
|
||||
|
||||
Therefore, when you are looking for multiple items, simply break
|
||||
them up into references like this, bundle them into a list. This
|
||||
function then runs through the list, and returns an amalgamated
|
||||
list of ``Verse`` objects. For example::
|
||||
|
||||
[(u'Genesis', 1, 1, 1), (u'Genesis', 2, 2, 3)]
|
||||
"""
|
||||
log.debug(u'BibleDB.get_verses: %s', reference_list)
|
||||
verse_list = []
|
||||
for book, chapter, start_verse, end_verse in reference_list:
|
||||
db_book = self.get_book(book)
|
||||
if end_verse == -1:
|
||||
end_verse = self.get_verse_count(book, chapter)
|
||||
if db_book:
|
||||
book = db_book.name
|
||||
log.debug(u'Book name corrected to "%s"', book)
|
||||
verses = self.session.query(Verse)\
|
||||
.filter_by(book_id=db_book.id)\
|
||||
.filter_by(chapter=chapter)\
|
||||
.filter(Verse.verse >= start_verse)\
|
||||
.filter(Verse.verse <= end_verse)\
|
||||
.order_by(Verse.verse)\
|
||||
.all()
|
||||
verse_list.extend(verses)
|
||||
return verse_list
|
||||
|
||||
def verse_search(self, text):
|
||||
"""
|
||||
Search for verses containing text ``text``.
|
||||
|
||||
``text``
|
||||
The text to search for. If the text contains commas, it will be
|
||||
split apart and OR'd on the list of values. If the text just
|
||||
contains spaces, it will split apart and AND'd on the list of
|
||||
values.
|
||||
"""
|
||||
log.debug(u'BibleDB.verse_search("%s")', text)
|
||||
verses = self.session.query(Verse)
|
||||
if text.find(u',') > -1:
|
||||
or_clause = []
|
||||
keywords = [u'%%%s%%' % keyword.strip() for keyword in text.split(u',')]
|
||||
for keyword in keywords:
|
||||
or_clause.append(Verse.text.like(keyword))
|
||||
verses = verses.filter(or_(*or_clause))
|
||||
else:
|
||||
keywords = [u'%%%s%%' % keyword.strip() for keyword in text.split(u' ')]
|
||||
for keyword in keywords:
|
||||
verses = verses.filter(Verse.text.like(keyword))
|
||||
verses = verses.all()
|
||||
return verses
|
||||
|
||||
def get_chapter_count(self, book):
|
||||
log.debug(u'BibleDB.get_chapter_count("%s")', book)
|
||||
count = self.session.query(Verse.chapter).join(Book)\
|
||||
.filter(Book.name==book)\
|
||||
.distinct().count()
|
||||
#verse = self.session.query(Verse).join(Book).filter(
|
||||
# Book.name == bookname).order_by(Verse.chapter.desc()).first()
|
||||
if not count:
|
||||
return 0
|
||||
else:
|
||||
return count
|
||||
|
||||
def get_verse_count(self, book, chapter):
|
||||
log.debug(u'BibleDB.get_verse_count("%s", %s)', book, chapter)
|
||||
count = self.session.query(Verse).join(Book)\
|
||||
.filter(Book.name==book)\
|
||||
.filter(Verse.chapter==chapter)\
|
||||
.count()
|
||||
#verse = self.session.query(Verse).join(Book).filter(
|
||||
# Book.name == bookname).filter(
|
||||
# Verse.chapter == chapter).order_by(Verse.verse.desc()).first()
|
||||
if not count:
|
||||
return 0
|
||||
else:
|
||||
return count
|
||||
|
||||
def get_meta(self, key):
|
||||
log.debug(u'get meta %s', key)
|
||||
return self.session.query(BibleMeta).get(key)
|
||||
|
||||
def delete_meta(self, metakey):
|
||||
biblemeta = self.get_meta(metakey)
|
||||
try:
|
||||
self.session.delete(biblemeta)
|
||||
self.commit()
|
||||
return True
|
||||
except:
|
||||
return False
|
||||
|
||||
def dump_bible(self):
|
||||
log.debug(u'.........Dumping Bible Database')
|
||||
log.debug('...............................Books ')
|
||||
books = self.session.query(Book).all()
|
||||
log.debug(books)
|
||||
log.debug(u'...............................Verses ')
|
||||
verses = self.session.query(Verse).all()
|
||||
log.debug(verses)
|
||||
|
|
@ -0,0 +1,365 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
|
||||
|
||||
###############################################################################
|
||||
# OpenLP - Open Source Lyrics Projection #
|
||||
# --------------------------------------------------------------------------- #
|
||||
# Copyright (c) 2008-2010 Raoul Snyman #
|
||||
# Portions copyright (c) 2008-2010 Tim Bentley, Jonathan Corwin, Michael #
|
||||
# Gorven, Scott Guerrieri, Maikel Stuivenberg, Martin Thompson, Jon Tibble, #
|
||||
# Carsten Tinggaard #
|
||||
# --------------------------------------------------------------------------- #
|
||||
# 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 urllib2
|
||||
import os
|
||||
import sqlite3
|
||||
|
||||
from BeautifulSoup import BeautifulSoup
|
||||
|
||||
from openlp.core.lib import Receiver
|
||||
from common import BibleCommon, SearchResults
|
||||
from db import BibleDB
|
||||
from openlp.plugins.bibles.lib.models import Book
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
class HTTPBooks(object):
|
||||
cursor = None
|
||||
|
||||
@staticmethod
|
||||
def get_cursor():
|
||||
if HTTPBooks.cursor is None:
|
||||
filepath = os.path.join(os.path.dirname(os.path.abspath(__file__)),
|
||||
u'..', u'resources', u'httpbooks.sqlite')
|
||||
conn = sqlite3.connect(filepath)
|
||||
HTTPBooks.cursor = conn.cursor()
|
||||
return HTTPBooks.cursor
|
||||
|
||||
@staticmethod
|
||||
def run_sql(query, parameters=()):
|
||||
cursor = HTTPBooks.get_cursor()
|
||||
cursor.execute(query, parameters)
|
||||
return cursor.fetchall()
|
||||
|
||||
@staticmethod
|
||||
def get_books():
|
||||
books = HTTPBooks.run_sql(u'SELECT id, testament_id, name, '
|
||||
u'abbreviation, chapters FROM books ORDER BY id')
|
||||
book_list = []
|
||||
for book in books:
|
||||
book_list.append({
|
||||
u'id': book[0],
|
||||
u'testament_id': book[1],
|
||||
u'name': unicode(book[2]),
|
||||
u'abbreviation': unicode(book[3]),
|
||||
u'chapters': book[4]
|
||||
})
|
||||
return book_list
|
||||
|
||||
@staticmethod
|
||||
def get_book(name):
|
||||
if not isinstance(name, unicode):
|
||||
name = unicode(name)
|
||||
books = HTTPBooks.run_sql(u'SELECT id, testament_id, name, '
|
||||
u'abbreviation, chapters FROM books WHERE name = ? OR '
|
||||
u'abbreviation = ?', (name, name))
|
||||
if books:
|
||||
return {
|
||||
u'id': books[0][0],
|
||||
u'testament_id': books[0][1],
|
||||
u'name': unicode(books[0][2]),
|
||||
u'abbreviation': unicode(books[0][3]),
|
||||
u'chapters': books[0][4]
|
||||
}
|
||||
else:
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def get_chapter(name, chapter):
|
||||
if not isinstance(name, int):
|
||||
chapter = int(chapter)
|
||||
book = HTTPBooks.get_book(name)
|
||||
chapters = HTTPBooks.run_sql(u'SELECT id, book_id, chapter, '
|
||||
u'verses FROM chapters WHERE book_id = ?', (book[u'id'],))
|
||||
if chapters:
|
||||
return {
|
||||
u'id': chapters[0][0],
|
||||
u'book_id': chapters[0][1],
|
||||
u'chapter': chapters[0][2],
|
||||
u'verses': chapters[0][3]
|
||||
}
|
||||
else:
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def get_chapter_count(book):
|
||||
details = HTTPBooks.get_book(book)
|
||||
if details:
|
||||
return details[u'chapters']
|
||||
return 0
|
||||
|
||||
@staticmethod
|
||||
def get_verse_count(book, chapter):
|
||||
details = HTTPBooks.get_chapter(book, chapter)
|
||||
if details:
|
||||
return details[u'verses']
|
||||
return 0
|
||||
|
||||
|
||||
class BGExtract(BibleCommon):
|
||||
log.info(u'%s BGExtract loaded', __name__)
|
||||
|
||||
def __init__(self, proxyurl=None):
|
||||
log.debug(u'init %s', proxyurl)
|
||||
self.proxyurl = proxyurl
|
||||
|
||||
def get_bible_chapter(self, version, bookname, chapter) :
|
||||
"""
|
||||
Access and decode bibles via the BibleGateway website
|
||||
|
||||
``Version``
|
||||
The version of the bible like 31 for New International version
|
||||
|
||||
``bookname``
|
||||
Name of the Book
|
||||
|
||||
``chapter``
|
||||
Chapter number
|
||||
"""
|
||||
log.debug(u'get_bible_chapter %s, %s, %s', version, bookname, chapter)
|
||||
urlstring = u'http://www.biblegateway.com/passage/?search=%s+%s' \
|
||||
u'&version=%s' % (bookname, chapter, version)
|
||||
log.debug(u'BibleGateway url = %s' % urlstring)
|
||||
xml_string = self._get_web_text(urlstring, self.proxyurl)
|
||||
verseSearch = u'<sup class=\"versenum'
|
||||
verseFootnote = u'<sup class=\'footnote'
|
||||
verse = 1
|
||||
i = xml_string.find(u'result-text-style-normal') + 26
|
||||
xml_string = xml_string[i:len(xml_string)]
|
||||
versePos = xml_string.find(verseSearch)
|
||||
bible = {}
|
||||
while versePos > -1:
|
||||
# clear out string
|
||||
verseText = u''
|
||||
versePos = xml_string.find(u'</sup>', versePos) + 6
|
||||
i = xml_string.find(verseSearch, versePos + 1)
|
||||
# Not sure if this is needed now
|
||||
if i == -1:
|
||||
i = xml_string.find(u'</div', versePos + 1)
|
||||
j = xml_string.find(u'<strong', versePos + 1)
|
||||
if j > 0 and j < i:
|
||||
i = j
|
||||
verseText = xml_string[versePos + 7 : i ]
|
||||
# store the verse
|
||||
bible[verse] = self._clean_text(verseText)
|
||||
versePos = -1
|
||||
else:
|
||||
verseText = xml_string[versePos: i]
|
||||
start_tag = verseText.find(verseFootnote)
|
||||
while start_tag > -1:
|
||||
end_tag = verseText.find(u'</sup>')
|
||||
verseText = verseText[:start_tag] + verseText[end_tag + 6:len(verseText)]
|
||||
start_tag = verseText.find(verseFootnote)
|
||||
# Chop off verse and start again
|
||||
xml_string = xml_string[i:]
|
||||
#look for the next verse
|
||||
versePos = xml_string.find(verseSearch)
|
||||
# store the verse
|
||||
bible[verse] = self._clean_text(verseText)
|
||||
verse += 1
|
||||
return SearchResults(bookname, chapter, bible)
|
||||
|
||||
class CWExtract(BibleCommon):
|
||||
log.info(u'%s CWExtract loaded', __name__)
|
||||
|
||||
def __init__(self, proxyurl=None):
|
||||
log.debug(u'init %s', proxyurl)
|
||||
self.proxyurl = proxyurl
|
||||
|
||||
def get_bible_chapter(self, version, bookname, chapter):
|
||||
log.debug(u'%s %s, %s, %s', __name__, version, bookname, chapter)
|
||||
"""
|
||||
Access and decode bibles via the Crosswalk website
|
||||
|
||||
``version``
|
||||
The version of the bible like niv for New International Version
|
||||
|
||||
``bookname``
|
||||
Text name of in english e.g. 'gen' for Genesis
|
||||
|
||||
``chapter``
|
||||
Chapter number
|
||||
"""
|
||||
log.debug(u'get_bible_chapter %s,%s,%s',
|
||||
version, bookname, chapter)
|
||||
bookname = bookname.replace(u' ', u'')
|
||||
chapter_url = u'http://www.biblestudytools.com/%s/%s/%s.html' % \
|
||||
(version, bookname.lower(), chapter)
|
||||
log.debug(u'URL: %s', chapter_url)
|
||||
page = urllib2.urlopen(chapter_url)
|
||||
if not page:
|
||||
return None
|
||||
soup = BeautifulSoup(page)
|
||||
htmlverses = soup.findAll(u'span', u'versetext')
|
||||
verses = {}
|
||||
for verse in htmlverses:
|
||||
Receiver.send_message(u'process_events')
|
||||
versenumber = int(verse.contents[0].contents[0])
|
||||
versetext = u''
|
||||
for part in verse.contents:
|
||||
if str(part)[0] != u'<':
|
||||
versetext = versetext + part
|
||||
elif part and part.attrMap and part.attrMap[u'class'] == u'WordsOfChrist':
|
||||
for subpart in part.contents:
|
||||
if str(subpart)[0] != '<':
|
||||
versetext = versetext + subpart
|
||||
versetext = versetext.strip(u'\n\r\t ')
|
||||
verses[versenumber] = versetext
|
||||
return SearchResults(bookname, chapter, verses)
|
||||
|
||||
|
||||
class HTTPBible(BibleDB):
|
||||
log.info(u'%s HTTPBible loaded' , __name__)
|
||||
|
||||
def __init__(self, parent, **kwargs):
|
||||
"""
|
||||
Finds all the bibles defined for the system
|
||||
Creates an Interface Object for each bible containing connection
|
||||
information
|
||||
|
||||
Throws Exception if no Bibles are found.
|
||||
|
||||
Init confirms the bible exists and stores the database path.
|
||||
"""
|
||||
BibleDB.__init__(self, parent, **kwargs)
|
||||
if u'download_source' not in kwargs:
|
||||
raise KeyError(u'Missing keyword argument "download_source"')
|
||||
if u'download_name' not in kwargs:
|
||||
raise KeyError(u'Missing keyword argument "download_name"')
|
||||
self.download_source = kwargs[u'download_source']
|
||||
self.download_name = kwargs[u'download_name']
|
||||
if u'proxy_server' in kwargs:
|
||||
self.proxy_server = kwargs[u'proxy_server']
|
||||
else:
|
||||
self.proxy_server = None
|
||||
if u'proxy_username' in kwargs:
|
||||
self.proxy_username = kwargs[u'proxy_username']
|
||||
else:
|
||||
self.proxy_username = None
|
||||
if u'proxy_password' in kwargs:
|
||||
self.proxy_password = kwargs[u'proxy_password']
|
||||
else:
|
||||
self.proxy_password = None
|
||||
|
||||
def do_import(self):
|
||||
self.wizard.ImportProgressBar.setMaximum(2)
|
||||
self.wizard.incrementProgressBar('Registering bible...')
|
||||
self.create_meta(u'download source', self.download_source)
|
||||
self.create_meta(u'download name', self.download_name)
|
||||
if self.proxy_server:
|
||||
self.create_meta(u'proxy server', self.proxy_server)
|
||||
if self.proxy_username:
|
||||
# store the proxy userid
|
||||
self.create_meta(u'proxy username', self.proxy_username)
|
||||
if self.proxy_password:
|
||||
# store the proxy password
|
||||
self.create_meta(u'proxy password', self.proxy_password)
|
||||
self.wizard.incrementProgressBar('Registered.')
|
||||
return True
|
||||
|
||||
def get_verses(self, reference_list):
|
||||
"""
|
||||
A reimplementation of the ``BibleDB.get_verses`` method, this one is
|
||||
specifically for web Bibles. It first checks to see if the particular
|
||||
chapter exists in the DB, and if not it pulls it from the web. If the
|
||||
chapter DOES exist, it simply pulls the verses from the DB using the
|
||||
ancestor method.
|
||||
|
||||
``reference_list``
|
||||
This is the list of references the media manager item wants. It is
|
||||
a list of tuples, with the following format::
|
||||
|
||||
(book, chapter, start_verse, end_verse)
|
||||
|
||||
Therefore, when you are looking for multiple items, simply break
|
||||
them up into references like this, bundle them into a list. This
|
||||
function then runs through the list, and returns an amalgamated
|
||||
list of ``Verse`` objects. For example::
|
||||
|
||||
[(u'Genesis', 1, 1, 1), (u'Genesis', 2, 2, 3)]
|
||||
"""
|
||||
for reference in reference_list:
|
||||
log.debug('Reference: %s', reference)
|
||||
book = reference[0]
|
||||
db_book = self.get_book(book)
|
||||
if not db_book:
|
||||
book_details = self.lookup_book(book)
|
||||
if not book_details:
|
||||
Receiver.send_message(u'bible_nobook')
|
||||
return []
|
||||
db_book = self.create_book(book_details[u'name'],
|
||||
book_details[u'abbreviation'], book_details[u'testament_id'])
|
||||
book = db_book.name
|
||||
if BibleDB.get_verse_count(self, book, reference[1]) == 0:
|
||||
Receiver.send_message(u'bible_showprogress')
|
||||
Receiver.send_message(u'process_events')
|
||||
search_results = self.get_chapter(self.name, book, reference[1])
|
||||
if search_results and search_results.has_verselist():
|
||||
## We have found a book of the bible lets check to see
|
||||
## if it was there. By reusing the returned book name
|
||||
## we get a correct book. For example it is possible
|
||||
## to request ac and get Acts back.
|
||||
bookname = search_results.get_book()
|
||||
# check to see if book/chapter exists
|
||||
db_book = self.get_book(bookname)
|
||||
self.create_chapter(db_book.id, search_results.get_chapter(),
|
||||
search_results.get_verselist())
|
||||
Receiver.send_message(u'bible_hideprogress')
|
||||
Receiver.send_message(u'process_events')
|
||||
return BibleDB.get_verses(self, reference_list)
|
||||
|
||||
def get_chapter(self, version, book, chapter):
|
||||
"""
|
||||
Receive the request and call the relevant handler methods
|
||||
"""
|
||||
log.debug(u'get_chapter %s, %s, %s', version, book, chapter)
|
||||
log.debug(u'source = %s', self.download_source)
|
||||
try:
|
||||
if self.download_source.lower() == u'crosswalk':
|
||||
ev = CWExtract(self.proxy_server)
|
||||
else:
|
||||
ev = BGExtract(self.proxy_server)
|
||||
return ev.get_bible_chapter(self.download_name, book, chapter)
|
||||
except:
|
||||
log.exception("Failed to get bible chapter")
|
||||
return None
|
||||
|
||||
def get_books(self):
|
||||
return [Book.populate(name=book['name']) for book in HTTPBooks.get_books()]
|
||||
|
||||
def lookup_book(self, book):
|
||||
return HTTPBooks.get_book(book)
|
||||
|
||||
def get_chapter_count(self, book):
|
||||
return HTTPBooks.get_chapter_count(book)
|
||||
|
||||
def get_verse_count(self, book, chapter):
|
||||
return HTTPBooks.get_verse_count(book, chapter)
|
||||
|
||||
def set_proxy_server(self, server):
|
||||
self.proxy_server = server
|
||||
|
|
@ -26,340 +26,202 @@
|
|||
import logging
|
||||
import os
|
||||
|
||||
from bibleOpenSongimpl import BibleOpenSongImpl
|
||||
from bibleOSISimpl import BibleOSISImpl
|
||||
from bibleCSVimpl import BibleCSVImpl
|
||||
from bibleDBimpl import BibleDBImpl
|
||||
from bibleHTTPimpl import BibleHTTPImpl
|
||||
from common import parse_reference
|
||||
from opensong import OpenSongBible
|
||||
from osis import OSISBible
|
||||
from csvbible import CSVBible
|
||||
from db import BibleDB
|
||||
from http import HTTPBible
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
class BibleMode(object):
|
||||
"""
|
||||
This is basically an enumeration class which specifies the mode of a Bible.
|
||||
Mode refers to whether or not a Bible in OpenLP is a full Bible or needs to
|
||||
be downloaded from the Internet on an as-needed basis.
|
||||
"""
|
||||
Full = 1
|
||||
Partial = 2
|
||||
|
||||
|
||||
class BibleFormat(object):
|
||||
"""
|
||||
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.
|
||||
"""
|
||||
Unknown = -1
|
||||
OSIS = 0
|
||||
CSV = 1
|
||||
OpenSong = 2
|
||||
WebDownload = 3
|
||||
|
||||
@classmethod
|
||||
def get_handler(class_, id):
|
||||
if id == class_.OSIS:
|
||||
return BibleOSISImpl
|
||||
elif id == class_.CSV:
|
||||
return BibleCSVImpl
|
||||
elif id == class_.OpenSong:
|
||||
return BibleOpenSongImpl
|
||||
elif id == class_.WebDownload:
|
||||
return BibleHTTPImpl
|
||||
@staticmethod
|
||||
def get_class(id):
|
||||
"""
|
||||
Return the appropriate imeplementation class.
|
||||
"""
|
||||
if id == BibleFormat.OSIS:
|
||||
return OSISBible
|
||||
elif id == BibleFormat.CSV:
|
||||
return CSVBible
|
||||
elif id == BibleFormat.OpenSong:
|
||||
return OpenSongBible
|
||||
elif id == BibleFormat.WebDownload:
|
||||
return HTTPBible
|
||||
else:
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def list():
|
||||
return [
|
||||
BibleFormat.OSIS,
|
||||
BibleFormat.CSV,
|
||||
BibleFormat.OpenSong,
|
||||
BibleFormat.WebDownload
|
||||
]
|
||||
|
||||
|
||||
class BibleManager(object):
|
||||
"""
|
||||
The Bible manager which holds and manages all the Bibles.
|
||||
"""
|
||||
global log
|
||||
log = logging.getLogger(u'BibleManager')
|
||||
log.info(u'Bible manager loaded')
|
||||
|
||||
def __init__(self, config):
|
||||
def __init__(self, parent, config):
|
||||
"""
|
||||
Finds all the bibles defined for the system and creates an
|
||||
interface object for each bible containing connection
|
||||
information. Throws Exception if no Bibles are found.
|
||||
Finds all the bibles defined for the system and creates an interface
|
||||
object for each bible containing connection information. Throws
|
||||
Exception if no Bibles are found.
|
||||
|
||||
Init confirms the bible exists and stores the database path.
|
||||
|
||||
``config``
|
||||
The plugin's configuration object.
|
||||
"""
|
||||
self.config = config
|
||||
log.debug(u'Bible Initialising')
|
||||
self.config = config
|
||||
self.parent = parent
|
||||
self.web = u'Web'
|
||||
# dict of bible database objects
|
||||
self.bible_db_cache = None
|
||||
# dict of bible http readers
|
||||
self.bible_http_cache = None
|
||||
self.biblePath = self.config.get_data_path()
|
||||
#get proxy name for screen
|
||||
self.proxyname = self.config.get_config(u'proxy name')
|
||||
self.bibleSuffix = u'sqlite'
|
||||
self.dialogobject = None
|
||||
self.db_cache = None
|
||||
self.path = self.config.get_data_path()
|
||||
self.proxy_name = self.config.get_config(u'proxy name')
|
||||
self.suffix = u'sqlite'
|
||||
self.import_wizard = None
|
||||
self.reload_bibles()
|
||||
self.media = None
|
||||
|
||||
def reload_bibles(self):
|
||||
"""
|
||||
Reloads the Bibles from the available Bible databases on disk. If a web
|
||||
Bible is encountered, an instance of HTTPBible is loaded instead of the
|
||||
BibleDB class.
|
||||
"""
|
||||
log.debug(u'Reload bibles')
|
||||
files = self.config.get_files(self.bibleSuffix)
|
||||
files = self.config.get_files(self.suffix)
|
||||
log.debug(u'Bible Files %s', files)
|
||||
self.bible_db_cache = {}
|
||||
self.bible_http_cache = {}
|
||||
# books of the bible with testaments
|
||||
self.book_testaments = {}
|
||||
# books of the bible with chapter count
|
||||
self.book_chapters = []
|
||||
# books of the bible with abbreviation
|
||||
self.book_abbreviations = {}
|
||||
self.web_bibles_present = False
|
||||
for f in files:
|
||||
nme = f.split(u'.')
|
||||
bname = nme[0]
|
||||
self.bible_db_cache[bname] = BibleDBImpl(self.biblePath,
|
||||
bname, self.config)
|
||||
self.db_cache = {}
|
||||
for filename in files:
|
||||
name, extension = os.path.splitext(filename)
|
||||
self.db_cache[name] = BibleDB(self.parent, path=self.path, name=name, config=self.config)
|
||||
# look to see if lazy load bible exists and get create getter.
|
||||
biblesource = self.bible_db_cache[bname].get_meta(u'WEB')
|
||||
if biblesource:
|
||||
self.web_bibles_present = True
|
||||
nhttp = BibleHTTPImpl()
|
||||
# tell The Server where to get the verses from.
|
||||
nhttp.set_bible_source(biblesource.value)
|
||||
self.bible_http_cache [bname] = nhttp
|
||||
# look to see if lazy load bible exists and get create getter.
|
||||
meta = self.bible_db_cache[bname].get_meta(u'proxy')
|
||||
proxy = None
|
||||
if meta:
|
||||
proxy = meta.value
|
||||
# tell The Server where to get the verses from.
|
||||
nhttp.set_proxy(proxy)
|
||||
# look to see if lazy load bible exists and get create getter.
|
||||
bibleid = self.bible_db_cache[bname].get_meta(u'bibleid').value
|
||||
# tell The Server where to get the verses from.
|
||||
nhttp.set_bibleid(bibleid)
|
||||
else:
|
||||
# makes the Full / partial code easier.
|
||||
self.bible_http_cache [bname] = None
|
||||
if self.web_bibles_present:
|
||||
# books of the bible linked to bibleid {osis, name}
|
||||
self.book_testaments = {}
|
||||
# books of the bible linked to bibleid {osis, abbrev}
|
||||
self.book_abbreviations = {}
|
||||
filepath = os.path.split(os.path.abspath(__file__))[0]
|
||||
filepath = os.path.abspath(os.path.join(
|
||||
filepath, u'..', u'resources',u'httpbooks.csv'))
|
||||
fbibles = None
|
||||
try:
|
||||
fbibles = open(filepath, u'r')
|
||||
for line in fbibles:
|
||||
p = line.split(u',')
|
||||
self.book_abbreviations[p[0]] = p[1].replace(u'\n', '')
|
||||
self.book_testaments[p[0]] = p[2].replace(u'\n', '')
|
||||
self.book_chapters.append({u'book':p[0], u'total':p[3].replace(u'\n', '')})
|
||||
except:
|
||||
log.exception(u'Failed to load bible')
|
||||
finally:
|
||||
if fbibles:
|
||||
fbibles.close()
|
||||
log.debug(u'Bible Initialised')
|
||||
source = self.db_cache[name].get_meta(u'download source')
|
||||
if source:
|
||||
download_name = self.db_cache[name].get_meta(u'download name').value
|
||||
meta_proxy = self.db_cache[name].get_meta(u'proxy url')
|
||||
web_bible = HTTPBible(self.parent, path=self.path, name=name,
|
||||
config=self.config, download_source=source.value,
|
||||
download_name=download_name)
|
||||
if meta_proxy:
|
||||
web_bible.set_proxy_server(meta_proxy.value)
|
||||
#del self.db_cache[name]
|
||||
self.db_cache[name] = web_bible
|
||||
log.debug(u'Bibles reloaded')
|
||||
|
||||
def set_process_dialog(self, dialogobject):
|
||||
def set_process_dialog(self, wizard):
|
||||
"""
|
||||
Sets the reference to the dialog with the progress bar on it.
|
||||
|
||||
``dialogobject``
|
||||
The reference to the dialog.
|
||||
``dialog``
|
||||
The reference to the import wizard.
|
||||
"""
|
||||
self.dialogobject = dialogobject
|
||||
self.import_wizard = wizard
|
||||
|
||||
def import_bible(self, type, **kwargs):
|
||||
"""
|
||||
Register a bible in the bible cache, and then import the verses.
|
||||
|
||||
``type``
|
||||
What type of Bible,
|
||||
What type of Bible, one of the ``BibleFormat`` values.
|
||||
|
||||
``**kwargs``
|
||||
Keyword arguments to send to the actual importer class.
|
||||
"""
|
||||
pass
|
||||
class_ = BibleFormat.get_class(type)
|
||||
kwargs['path'] = self.path
|
||||
kwargs['config'] = self.config
|
||||
importer = class_(self.parent, **kwargs)
|
||||
name = importer.register(self.import_wizard)
|
||||
self.db_cache[name] = importer
|
||||
return importer.do_import()
|
||||
|
||||
def register_http_bible(self, biblename, biblesource, bibleid,
|
||||
proxyurl=None, proxyid=None, proxypass=None):
|
||||
def get_bibles(self):
|
||||
"""
|
||||
Return a list of bibles from a given URL. The selected Bible
|
||||
can then be registered and LazyLoaded into a database.
|
||||
|
||||
``biblename``
|
||||
The name of the bible to register.
|
||||
|
||||
``biblesource``
|
||||
Where this Bible stores it's verses.
|
||||
|
||||
``bibleid``
|
||||
The identifier for a Bible.
|
||||
|
||||
``proxyurl``
|
||||
Defaults to *None*. An optional URL to a proxy server.
|
||||
|
||||
``proxyid``
|
||||
Defaults to *None*. A username for logging into the proxy
|
||||
server.
|
||||
|
||||
``proxypass``
|
||||
Defaults to *None*. The password to accompany the username.
|
||||
"""
|
||||
log.debug(u'register_HTTP_bible %s, %s, %s, %s, %s, %s',
|
||||
biblename, biblesource, bibleid, proxyurl, proxyid, proxypass)
|
||||
if self._is_new_bible(biblename):
|
||||
# Create new Bible
|
||||
nbible = BibleDBImpl(self.biblePath, biblename, self.config)
|
||||
# Create Database
|
||||
nbible.create_tables()
|
||||
self.bible_db_cache[biblename] = nbible
|
||||
nhttp = BibleHTTPImpl()
|
||||
nhttp.set_bible_source(biblesource)
|
||||
self.bible_http_cache[biblename] = nhttp
|
||||
# register a lazy loading interest
|
||||
nbible.save_meta(u'WEB', biblesource)
|
||||
# store the web id of the bible
|
||||
nbible.save_meta(u'bibleid', bibleid)
|
||||
if proxyurl:
|
||||
# store the proxy URL
|
||||
nbible.save_meta(u'proxy', proxyurl)
|
||||
nhttp.set_proxy(proxyurl)
|
||||
if proxyid:
|
||||
# store the proxy userid
|
||||
nbible.save_meta(u'proxyid', proxyid)
|
||||
if proxypass:
|
||||
# store the proxy password
|
||||
nbible.save_meta(u'proxypass', proxypass)
|
||||
return True
|
||||
else:
|
||||
log.debug(u'register_http_file_bible %s not created already exists',
|
||||
biblename)
|
||||
return False
|
||||
|
||||
def register_csv_file_bible(self, biblename, booksfile, versefile):
|
||||
"""
|
||||
Method to load a bible from a set of files into a database.
|
||||
If the database exists it is deleted and the database is reloaded
|
||||
from scratch.
|
||||
"""
|
||||
log.debug(u'register_CSV_file_bible %s,%s,%s',
|
||||
biblename, booksfile, versefile)
|
||||
if self._is_new_bible(biblename):
|
||||
# Create new Bible
|
||||
nbible = BibleDBImpl(self.biblePath, biblename, self.config)
|
||||
# Create database
|
||||
nbible.create_tables()
|
||||
# Cache the database for use later
|
||||
self.bible_db_cache[biblename] = nbible
|
||||
# Create the loader and pass in the database
|
||||
bcsv = BibleCSVImpl(nbible)
|
||||
return bcsv.load_data(booksfile, versefile, self.dialogobject)
|
||||
else:
|
||||
log.debug(u'register_csv_file_bible %s not created already exists',
|
||||
biblename)
|
||||
return False
|
||||
|
||||
def register_osis_file_bible(self, biblename, osisfile):
|
||||
"""
|
||||
Method to load a bible from a osis xml file extracted from Sword bible
|
||||
viewer. If the database exists it is deleted and the database is
|
||||
reloaded from scratch.
|
||||
"""
|
||||
log.debug(u'register_OSIS_file_bible %s, %s', biblename, osisfile)
|
||||
if self._is_new_bible(biblename):
|
||||
# Create new Bible
|
||||
nbible = BibleDBImpl(self.biblePath, biblename, self.config)
|
||||
# Create Database
|
||||
nbible.create_tables()
|
||||
# Cache the database for use later
|
||||
self.bible_db_cache[biblename] = nbible
|
||||
# Create the loader and pass in the database
|
||||
bosis = BibleOSISImpl(self.biblePath, nbible)
|
||||
return bosis.load_data(osisfile, self.dialogobject)
|
||||
else:
|
||||
log.debug(
|
||||
u'register_OSIS_file_bible %s, %s not created already exists',
|
||||
biblename, osisfile)
|
||||
return False
|
||||
|
||||
def register_opensong_bible(self, biblename, opensongfile):
|
||||
"""
|
||||
Method to load a bible from an OpenSong xml file. If the database
|
||||
exists it is deleted and the database is reloaded from scratch.
|
||||
"""
|
||||
log.debug(u'register_opensong_file_bible %s, %s', biblename, opensongfile)
|
||||
if self._is_new_bible(biblename):
|
||||
# Create new Bible
|
||||
nbible = BibleDBImpl(self.biblePath, biblename, self.config)
|
||||
# Create Database
|
||||
nbible.create_tables()
|
||||
# Cache the database for use later
|
||||
self.bible_db_cache[biblename] = nbible
|
||||
# Create the loader and pass in the database
|
||||
bcsv = BibleOpenSongImpl(self.biblePath, nbible)
|
||||
bcsv.load_data(opensongfile, self.dialogobject)
|
||||
return True
|
||||
else:
|
||||
log.debug(u'register_opensong_file_bible %s, %s not created '
|
||||
u'already exists', biblename, opensongfile)
|
||||
return False
|
||||
|
||||
def get_bibles(self, mode=BibleMode.Full):
|
||||
"""
|
||||
Returns a list of Books of the bible. When ``mode`` is set to
|
||||
``BibleMode.Full`` this method returns all the Bibles for the
|
||||
Advanced Search, and when the mode is ``BibleMode.Partial``
|
||||
this method returns all the bibles for the Quick Search.
|
||||
Returns a list of the names of available Bibles.
|
||||
"""
|
||||
log.debug(u'get_bibles')
|
||||
bible_list = []
|
||||
for bible_name, bible_object in self.bible_db_cache.iteritems():
|
||||
if self.bible_http_cache[bible_name]:
|
||||
bible_name = u'%s (%s)' % (bible_name, self.web)
|
||||
bible_list.append(bible_name)
|
||||
return bible_list
|
||||
return [name for name, bible in self.db_cache.iteritems()]
|
||||
|
||||
def is_bible_web(self, bible):
|
||||
pos_end = bible.find(u' (%s)' % self.web)
|
||||
if pos_end != -1:
|
||||
return True, bible[:pos_end]
|
||||
return False, bible
|
||||
|
||||
def get_bible_books(self):
|
||||
def get_books(self, bible):
|
||||
"""
|
||||
Returns a list of the books of the bible
|
||||
"""
|
||||
log.debug(u'get_bible_books')
|
||||
return self.book_chapters
|
||||
Returns a list of Bible books, and the number of chapters in that book.
|
||||
|
||||
def get_book_chapter_count(self, book):
|
||||
``bible``
|
||||
Unicode. The Bible to get the list of books from.
|
||||
"""
|
||||
log.debug(u'BibleManager.get_books("%s")', bible)
|
||||
return [
|
||||
{
|
||||
u'name': book.name,
|
||||
u'chapters': self.db_cache[bible].get_chapter_count(book.name)
|
||||
}
|
||||
for book in self.db_cache[bible].get_books()
|
||||
]
|
||||
|
||||
def get_chapter_count(self, bible, book):
|
||||
"""
|
||||
Returns the number of Chapters for a given book
|
||||
"""
|
||||
log.debug(u'get_book_chapter_count %s', book)
|
||||
return self.book_chapters[book]
|
||||
return self.db_cache[bible].get_chapter_count(book)
|
||||
|
||||
def get_book_verse_count(self, bible, book, chapter):
|
||||
def get_verse_count(self, bible, book, chapter):
|
||||
"""
|
||||
Returns all the number of verses for a given
|
||||
book and chapterMaxBibleBookVerses
|
||||
"""
|
||||
log.debug(u'get_book_verse_count %s,%s,%s', bible, book, chapter)
|
||||
web, bible = self.is_bible_web(bible)
|
||||
if web:
|
||||
count = self.bible_db_cache[bible].get_max_bible_book_verses(
|
||||
book, chapter)
|
||||
if count == 0:
|
||||
# Make sure the first chapter has been downloaded
|
||||
self.get_verse_text(bible, book, chapter, chapter, 1, 1)
|
||||
count = self.bible_db_cache[bible].get_max_bible_book_verses(
|
||||
book, chapter)
|
||||
return count
|
||||
else:
|
||||
return self.bible_db_cache[bible].get_max_bible_book_verses(
|
||||
book, chapter)
|
||||
log.debug(u'BibleManager.get_verse_count("%s", "%s", %s)', bible, book, chapter)
|
||||
return self.db_cache[bible].get_verse_count(book, chapter)
|
||||
|
||||
def get_verse_from_text(self, bible, versetext):
|
||||
def get_verses(self, bible, versetext):
|
||||
"""
|
||||
Returns all the number of verses for a given
|
||||
book and chapterMaxBibleBookVerses
|
||||
Parses a scripture reference, fetches the verses from the Bible
|
||||
specified, and returns a list of ``Verse`` objects.
|
||||
|
||||
``bible``
|
||||
Unicode. The Bible to use.
|
||||
|
||||
``versetext``
|
||||
Unicode. The scripture reference. Valid scripture references are:
|
||||
|
||||
- Genesis 1:1
|
||||
- Genesis 1:1-10
|
||||
- Genesis 1:1-2:10
|
||||
"""
|
||||
log.debug(u'get_verses_from_text %s,%s', bible, versetext)
|
||||
web, bible = self.is_bible_web(bible)
|
||||
return self.bible_db_cache[bible].get_verses_from_text(versetext)
|
||||
log.debug(u'BibleManager.get_verses("%s", "%s")', bible, versetext)
|
||||
reflist = parse_reference(versetext)
|
||||
return self.db_cache[bible].get_verses(reflist)
|
||||
|
||||
def save_meta_data(self, bible, version, copyright, permissions):
|
||||
"""
|
||||
|
@ -367,124 +229,28 @@ class BibleManager(object):
|
|||
"""
|
||||
log.debug(u'save_meta data %s,%s, %s,%s',
|
||||
bible, version, copyright, permissions)
|
||||
self.bible_db_cache[bible].save_meta(u'Version', version)
|
||||
self.bible_db_cache[bible].save_meta(u'Copyright', copyright)
|
||||
self.bible_db_cache[bible].save_meta(u'Permissions', permissions)
|
||||
self.db_cache[bible].create_meta(u'Version', version)
|
||||
self.db_cache[bible].create_meta(u'Copyright', copyright)
|
||||
self.db_cache[bible].create_meta(u'Permissions', permissions)
|
||||
|
||||
def get_meta_data(self, bible, key):
|
||||
"""
|
||||
Returns the meta data for a given key
|
||||
"""
|
||||
log.debug(u'get_meta %s,%s', bible, key)
|
||||
web, bible = self.is_bible_web(bible)
|
||||
return self.bible_db_cache[bible].get_meta(key)
|
||||
return self.db_cache[bible].get_meta(key)
|
||||
|
||||
def get_verse_text(self, bible, bookname, schapter, echapter, sverse,
|
||||
everse=0):
|
||||
"""
|
||||
Returns a list of verses for a given Book, Chapter and ranges of verses.
|
||||
If the end verse(everse) is less then the start verse(sverse)
|
||||
then only one verse is returned
|
||||
|
||||
``bible``
|
||||
The name of the bible to be used
|
||||
|
||||
Rest can be guessed at !
|
||||
"""
|
||||
text = []
|
||||
self.media.setQuickMessage(u'')
|
||||
log.debug(u'get_verse_text %s,%s,%s,%s,%s,%s',
|
||||
bible, bookname, schapter, echapter, sverse, everse)
|
||||
# check to see if book/chapter exists fow HTTP bibles and load cache
|
||||
# if necessary
|
||||
web, bible = self.is_bible_web(bible)
|
||||
if self.bible_http_cache[bible]:
|
||||
book = self.bible_db_cache[bible].get_bible_book(bookname)
|
||||
if book is None:
|
||||
log.debug(u'get_verse_text : new book')
|
||||
for chapter in range(schapter, echapter + 1):
|
||||
self.media.setQuickMessage(
|
||||
unicode(self.media.trUtf8('Downloading %s: %s')) %
|
||||
(bookname, chapter))
|
||||
search_results = \
|
||||
self.bible_http_cache[bible].get_bible_chapter(
|
||||
bible, bookname, chapter)
|
||||
if search_results.has_verselist() :
|
||||
## We have found a book of the bible lets check to see
|
||||
## if it was there. By reusing the returned book name
|
||||
## we get a correct book. For example it is possible
|
||||
## to request ac and get Acts back.
|
||||
bookname = search_results.get_book()
|
||||
# check to see if book/chapter exists
|
||||
book = self.bible_db_cache[bible].get_bible_book(
|
||||
bookname)
|
||||
if book is None:
|
||||
## Then create book, chapter and text
|
||||
book = self.bible_db_cache[bible].create_book(
|
||||
bookname, self.book_abbreviations[bookname],
|
||||
self.book_testaments[bookname])
|
||||
log.debug(u'New http book %s, %s, %s',
|
||||
book, book.id, book.name)
|
||||
self.bible_db_cache[bible].create_chapter(
|
||||
book.id, search_results.get_chapter(),
|
||||
search_results.get_verselist())
|
||||
else:
|
||||
## Book exists check chapter and texts only.
|
||||
v = self.bible_db_cache[bible].get_bible_chapter(
|
||||
book.id, chapter)
|
||||
if v is None:
|
||||
self.media.setQuickMessage(
|
||||
unicode(self.media.trUtf8('%Downloading %s: %s'))\
|
||||
% (bookname, chapter))
|
||||
self.bible_db_cache[bible].create_chapter(
|
||||
book.id, chapter,
|
||||
search_results.get_verselist())
|
||||
else:
|
||||
log.debug(u'get_verse_text : old book')
|
||||
for chapter in range(schapter, echapter + 1):
|
||||
v = self.bible_db_cache[bible].get_bible_chapter(
|
||||
book.id, chapter)
|
||||
if v is None:
|
||||
try:
|
||||
self.media.setQuickMessage(\
|
||||
unicode(self.media.trUtf8('Downloading %s: %s'))
|
||||
% (bookname, chapter))
|
||||
search_results = \
|
||||
self.bible_http_cache[bible].get_bible_chapter(
|
||||
bible, bookname, chapter)
|
||||
if search_results.has_verselist():
|
||||
self.bible_db_cache[bible].create_chapter(
|
||||
book.id, search_results.get_chapter(),
|
||||
search_results.get_verselist())
|
||||
except:
|
||||
log.exception(u'Problem getting scripture online')
|
||||
#Now get verses from database
|
||||
if schapter == echapter:
|
||||
text = self.bible_db_cache[bible].get_bible_text(bookname,
|
||||
schapter, sverse, everse)
|
||||
else:
|
||||
for i in range (schapter, echapter + 1):
|
||||
if i == schapter:
|
||||
start = sverse
|
||||
end = self.get_book_verse_count(bible, bookname, i)
|
||||
elif i == echapter:
|
||||
start = 1
|
||||
end = everse
|
||||
else:
|
||||
start = 1
|
||||
end = self.get_book_verse_count(bible, bookname, i)
|
||||
|
||||
txt = self.bible_db_cache[bible].get_bible_text(
|
||||
bookname, i, start, end)
|
||||
text.extend(txt)
|
||||
return text
|
||||
|
||||
def _is_new_bible(self, name):
|
||||
def exists(self, name):
|
||||
"""
|
||||
Check cache to see if new bible
|
||||
"""
|
||||
for bible, o in self.bible_db_cache.iteritems():
|
||||
if not isinstance(name, unicode):
|
||||
name = unicode(name)
|
||||
for bible, db_object in self.db_cache.iteritems():
|
||||
log.debug(u'Bible from cache in is_new_bible %s', bible)
|
||||
if not isinstance(bible, unicode):
|
||||
bible = unicode(bible)
|
||||
if bible == name:
|
||||
return False
|
||||
return True
|
||||
return True
|
||||
return False
|
||||
|
||||
|
|
|
@ -31,7 +31,8 @@ from PyQt4 import QtCore, QtGui
|
|||
from openlp.core.lib import MediaManagerItem, Receiver, str_to_bool, \
|
||||
BaseListWithDnD
|
||||
from openlp.plugins.bibles.forms import ImportWizardForm
|
||||
from openlp.plugins.bibles.lib.manager import BibleMode
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
class BibleListView(BaseListWithDnD):
|
||||
"""
|
||||
|
@ -41,13 +42,13 @@ class BibleListView(BaseListWithDnD):
|
|||
self.PluginName = u'Bibles'
|
||||
BaseListWithDnD.__init__(self, parent)
|
||||
|
||||
def resizeEvent(self, event):
|
||||
self.parent.onListViewResize(event.size().width(), event.size().width())
|
||||
|
||||
class BibleMediaItem(MediaManagerItem):
|
||||
"""
|
||||
This is the custom media manager item for Bibles.
|
||||
"""
|
||||
global log
|
||||
log = logging.getLogger(u'BibleMediaItem')
|
||||
log.info(u'Bible Media Item loaded')
|
||||
|
||||
def __init__(self, parent, icon, title):
|
||||
|
@ -56,6 +57,7 @@ class BibleMediaItem(MediaManagerItem):
|
|||
self.IconPath = u'songs/song'
|
||||
self.ListViewWithDnD_class = BibleListView
|
||||
self.servicePath = None
|
||||
self.lastReference = []
|
||||
MediaManagerItem.__init__(self, parent, icon, title)
|
||||
# place to store the search results
|
||||
self.search_results = {}
|
||||
|
@ -241,6 +243,24 @@ class BibleMediaItem(MediaManagerItem):
|
|||
QtCore.SIGNAL(u'pressed()'), self.onQuickSearchButton)
|
||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||
QtCore.SIGNAL(u'config_updated'), self.configUpdated)
|
||||
# Other stuff
|
||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||
QtCore.SIGNAL(u'bible_showprogress'), self.onSearchProgressShow)
|
||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||
QtCore.SIGNAL(u'bible_hideprogress'), self.onSearchProgressHide)
|
||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||
QtCore.SIGNAL(u'bible_nobook'), self.onNoBookFound)
|
||||
|
||||
def addListViewToToolBar(self):
|
||||
MediaManagerItem.addListViewToToolBar(self)
|
||||
# Progress Bar
|
||||
self.SearchProgress = QtGui.QProgressBar(self)
|
||||
self.SearchProgress.setFormat('%p%')
|
||||
self.SearchProgress.setMaximum(3)
|
||||
self.SearchProgress.setGeometry(self.ListView.geometry().left(),
|
||||
self.ListView.geometry().top(), 81, 23)
|
||||
self.SearchProgress.setVisible(False)
|
||||
self.SearchProgress.setObjectName(u'SearchProgress')
|
||||
|
||||
def configUpdated(self):
|
||||
if str_to_bool(
|
||||
|
@ -281,7 +301,7 @@ class BibleMediaItem(MediaManagerItem):
|
|||
|
||||
def initialise(self):
|
||||
log.debug(u'bible manager initialise')
|
||||
self.parent.biblemanager.media = self
|
||||
self.parent.manager.media = self
|
||||
self.loadBibles()
|
||||
self.configUpdated()
|
||||
log.debug(u'bible manager initialise complete')
|
||||
|
@ -301,23 +321,40 @@ class BibleMediaItem(MediaManagerItem):
|
|||
self.AdvancedSecondBibleComboBox.clear()
|
||||
self.QuickSecondBibleComboBox.addItem(u'')
|
||||
self.AdvancedSecondBibleComboBox.addItem(u'')
|
||||
bibles = self.parent.biblemanager.get_bibles(BibleMode.Full)
|
||||
bibles = self.parent.manager.get_bibles()
|
||||
# load bibles into the combo boxes
|
||||
first = True
|
||||
for bible in bibles:
|
||||
self.QuickVersionComboBox.addItem(bible)
|
||||
self.QuickSecondBibleComboBox.addItem(bible)
|
||||
# Without HTTP
|
||||
bibles = self.parent.biblemanager.get_bibles(BibleMode.Partial)
|
||||
first = True
|
||||
# load bibles into the combo boxes
|
||||
for bible in bibles:
|
||||
self.AdvancedVersionComboBox.addItem(bible)
|
||||
self.AdvancedSecondBibleComboBox.addItem(bible)
|
||||
if first:
|
||||
first = False
|
||||
# use the first bible as the trigger
|
||||
self.initialiseBible(bible)
|
||||
|
||||
def onListViewResize(self, width, height):
|
||||
self.SearchProgress.setGeometry(self.ListView.geometry().x(),
|
||||
(self.ListView.geometry().y() + self.ListView.geometry().height())\
|
||||
- 23, 81, 23)
|
||||
|
||||
def onSearchProgressShow(self):
|
||||
self.SearchProgress.setVisible(True)
|
||||
self.SearchProgress.setMinimum(0)
|
||||
self.SearchProgress.setMaximum(2)
|
||||
self.SearchProgress.setValue(1)
|
||||
|
||||
def onSearchProgressHide(self):
|
||||
self.SearchProgress.setVisible(False)
|
||||
|
||||
def onNoBookFound(self):
|
||||
QtGui.QMessageBox.critical(self,
|
||||
self.trUtf8('No Book Found'),
|
||||
self.trUtf8('No matching book could be found in this Bible.'),
|
||||
QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Ok),
|
||||
QtGui.QMessageBox.Ok
|
||||
)
|
||||
|
||||
def onAdvancedVersionComboBox(self):
|
||||
self.initialiseBible(
|
||||
unicode(self.AdvancedVersionComboBox.currentText()))
|
||||
|
@ -330,11 +367,8 @@ class BibleMediaItem(MediaManagerItem):
|
|||
self.AdvancedBookComboBox.itemData(item).toInt()[0])
|
||||
|
||||
def onNewClick(self):
|
||||
#self.bibleimportform = BibleImportForm(
|
||||
# self.parent.config, self.parent.biblemanager, self)
|
||||
#self.bibleimportform.exec_()
|
||||
self.bibleimportform = ImportWizardForm(self, self.parent.config,
|
||||
self.parent.biblemanager, self.parent)
|
||||
self.parent.manager, self.parent)
|
||||
self.bibleimportform.exec_()
|
||||
self.reloadBibles()
|
||||
|
||||
|
@ -343,14 +377,13 @@ class BibleMediaItem(MediaManagerItem):
|
|||
self.adjustComboBox(frm, self.verses, self.AdvancedToVerse)
|
||||
|
||||
def onAdvancedToChapter(self):
|
||||
text1 = unicode(self.AdvancedFromChapter.currentText())
|
||||
text2 = unicode(self.AdvancedToChapter.currentText())
|
||||
if text1 != text2:
|
||||
frm = unicode(self.AdvancedFromChapter.currentText())
|
||||
to = unicode(self.AdvancedToChapter.currentText())
|
||||
if frm != to:
|
||||
bible = unicode(self.AdvancedVersionComboBox.currentText())
|
||||
book = unicode(self.AdvancedBookComboBox.currentText())
|
||||
# get the verse count for new chapter
|
||||
verses = self.parent.biblemanager.get_book_verse_count(
|
||||
bible, book, int(text2))
|
||||
verses = self.parent.manager.get_verse_count(bible, book, int(to))
|
||||
self.adjustComboBox(1, verses, self.AdvancedToVerse)
|
||||
|
||||
def onAdvancedSearchButton(self):
|
||||
|
@ -361,10 +394,13 @@ class BibleMediaItem(MediaManagerItem):
|
|||
chapter_to = int(self.AdvancedToChapter.currentText())
|
||||
verse_from = int(self.AdvancedFromVerse.currentText())
|
||||
verse_to = int(self.AdvancedToVerse.currentText())
|
||||
self.search_results = self.parent.biblemanager.get_verse_text(
|
||||
bible, book, chapter_from, chapter_to, verse_from, verse_to)
|
||||
versetext = u'%s %s:%s-%s:%s' % (book, chapter_from, verse_from, \
|
||||
chapter_to, verse_to)
|
||||
self.search_results = self.parent.manager.get_verses(bible, versetext)
|
||||
if self.ClearAdvancedSearchComboBox.currentIndex() == 0:
|
||||
self.ListView.clear()
|
||||
self.lastReference = []
|
||||
self.lastReference.append(versetext)
|
||||
self.displayResults(bible)
|
||||
|
||||
def onAdvancedFromChapter(self):
|
||||
|
@ -373,7 +409,7 @@ class BibleMediaItem(MediaManagerItem):
|
|||
cf = int(self.AdvancedFromChapter.currentText())
|
||||
self.adjustComboBox(cf, self.chapters_from, self.AdvancedToChapter)
|
||||
# get the verse count for new chapter
|
||||
vse = self.parent.biblemanager.get_book_verse_count(bible, book, cf)
|
||||
vse = self.parent.manager.get_verse_count(bible, book, cf)
|
||||
self.adjustComboBox(1, vse, self.AdvancedFromVerse)
|
||||
self.adjustComboBox(1, vse, self.AdvancedToVerse)
|
||||
|
||||
|
@ -383,11 +419,9 @@ class BibleMediaItem(MediaManagerItem):
|
|||
text = unicode(self.QuickSearchEdit.displayText())
|
||||
if self.ClearQuickSearchComboBox.currentIndex() == 0:
|
||||
self.ListView.clear()
|
||||
if self.QuickSearchComboBox.currentIndex() == 1:
|
||||
self.search_results = self.parent.biblemanager.get_verse_from_text(
|
||||
bible, text)
|
||||
else:
|
||||
self.searchByReference(bible, text)
|
||||
self.lastReference = []
|
||||
self.lastReference.append(text)
|
||||
self.search_results = self.parent.manager.get_verses(bible, text)
|
||||
if self.search_results:
|
||||
self.displayResults(bible)
|
||||
|
||||
|
@ -400,60 +434,64 @@ class BibleMediaItem(MediaManagerItem):
|
|||
raw_slides = []
|
||||
raw_footer = []
|
||||
bible_text = u''
|
||||
service_item.autoPreviewAllowed = True
|
||||
#If we want to use a 2nd translation / version
|
||||
bible2 = u''
|
||||
if self.SearchTabWidget.currentIndex() == 0:
|
||||
bible2 = unicode(self.QuickSecondBibleComboBox.currentText())
|
||||
else:
|
||||
bible2 = unicode(self.AdvancedSecondBibleComboBox.currentText())
|
||||
if bible2:
|
||||
bible2_verses = []
|
||||
for scripture in self.lastReference:
|
||||
bible2_verses.extend(self.parent.manager.get_verses(bible2, scripture))
|
||||
bible2_version = self.parent.manager.get_meta_data(bible2, u'Version')
|
||||
bible2_copyright = self.parent.manager.get_meta_data(bible2, u'Copyright')
|
||||
bible2_permission = self.parent.manager.get_meta_data(bible2, u'Permission')
|
||||
# Let's loop through the main lot, and assemble our verses
|
||||
for item in items:
|
||||
bitem = self.ListView.item(item.row())
|
||||
text = unicode((bitem.data(QtCore.Qt.UserRole)).toString())
|
||||
search_verse = text[:text.find(u'(')]
|
||||
bible = text[text.find(u'(') + 1:-1]
|
||||
self.searchByReference(bible, search_verse)
|
||||
book = self.search_results[0].book.name
|
||||
chapter = unicode(self.search_results[0].chapter)
|
||||
verse = unicode(self.search_results[0].verse)
|
||||
text = self.search_results[0].text
|
||||
reference = bitem.data(QtCore.Qt.UserRole).toPyObject()
|
||||
bible = unicode(reference[QtCore.QString('bible')])
|
||||
book = unicode(reference[QtCore.QString('book')])
|
||||
chapter = unicode(reference[QtCore.QString('chapter')])
|
||||
verse = unicode(reference[QtCore.QString('verse')])
|
||||
text = unicode(reference[QtCore.QString('text')])
|
||||
version = unicode(reference[QtCore.QString('version')])
|
||||
copyright = unicode(reference[QtCore.QString('copyright')])
|
||||
permission = unicode(reference[QtCore.QString('permission')])
|
||||
if self.parent.settings_tab.display_style == 1:
|
||||
loc = self.formatVerse(old_chapter, chapter, verse, u'(u', u')')
|
||||
verse_text = self.formatVerse(old_chapter, chapter, verse, u'(u', u')')
|
||||
elif self.parent.settings_tab.display_style == 2:
|
||||
loc = self.formatVerse(old_chapter, chapter, verse, u'{', u'}')
|
||||
verse_text = self.formatVerse(old_chapter, chapter, verse, u'{', u'}')
|
||||
elif self.parent.settings_tab.display_style == 3:
|
||||
loc = self.formatVerse(old_chapter, chapter, verse, u'[', u']')
|
||||
verse_text = self.formatVerse(old_chapter, chapter, verse, u'[', u']')
|
||||
else:
|
||||
loc = self.formatVerse(old_chapter, chapter, verse, u'', u'')
|
||||
verse_text = self.formatVerse(old_chapter, chapter, verse, u'', u'')
|
||||
old_chapter = chapter
|
||||
footer = u'%s (%s %s)' % (book, self.version, self.copyright)
|
||||
#If not found throws and error so add.s
|
||||
try:
|
||||
raw_footer.index(footer)
|
||||
except:
|
||||
footer = u'%s (%s %s)' % (book, version, copyright)
|
||||
#If not found add to footer
|
||||
if footer not in raw_footer:
|
||||
raw_footer.append(footer)
|
||||
#If we want to use a 2nd translation / version
|
||||
bible2 = u''
|
||||
if self.SearchTabWidget.currentIndex() == 0:
|
||||
bible2 = unicode(self.QuickSecondBibleComboBox.currentText())
|
||||
else:
|
||||
bible2 = unicode(self.AdvancedSecondBibleComboBox.currentText())
|
||||
if len(bible2) > 0:
|
||||
self.searchByReference(bible2, search_verse)
|
||||
footer = u'%s (%s %s)' % (book, self.version, self.copyright)
|
||||
#If not found throws and error so add.s
|
||||
try:
|
||||
raw_footer.index(footer)
|
||||
except:
|
||||
if bible2:
|
||||
footer = u'%s (%s %s)' % (book, version, copyright)
|
||||
#If not found add to footer
|
||||
if footer not in raw_footer:
|
||||
raw_footer.append(footer)
|
||||
bible_text = u'%s %s \n\n\n %s %s)' % \
|
||||
(loc, text, loc, self.search_results[0].text)
|
||||
bible_text = u'%s %s \n\n %s %s' % \
|
||||
(verse_text, text, verse_text, bible2_verses[item.row()].text)
|
||||
raw_slides.append(bible_text)
|
||||
bible_text = u''
|
||||
else:
|
||||
#Paragraph style force new line per verse
|
||||
if self.parent.settings_tab.layout_style == 1:
|
||||
text = text + u'\n\n'
|
||||
bible_text = u'%s %s %s' % (bible_text, loc, text)
|
||||
bible_text = u'%s %s %s' % (bible_text, verse_text, text)
|
||||
#if we are verse per slide then create slide
|
||||
if self.parent.settings_tab.layout_style == 0:
|
||||
raw_slides.append(bible_text)
|
||||
bible_text = u''
|
||||
service_item.title = u'%s %s' % (book, loc)
|
||||
|
||||
service_item.title = u'%s %s' % (book, verse_text)
|
||||
if len(self.parent.settings_tab.bible_theme) == 0:
|
||||
service_item.theme = None
|
||||
else:
|
||||
|
@ -467,40 +505,39 @@ class BibleMediaItem(MediaManagerItem):
|
|||
return True
|
||||
|
||||
def formatVerse(self, old_chapter, chapter, verse, opening, closing):
|
||||
loc = opening
|
||||
verse_text = opening
|
||||
if old_chapter != chapter:
|
||||
loc += chapter + u':'
|
||||
verse_text += chapter + u':'
|
||||
elif not self.parent.settings_tab.show_new_chapters:
|
||||
loc += chapter + u':'
|
||||
loc += verse
|
||||
loc += closing
|
||||
return loc
|
||||
verse_text += chapter + u':'
|
||||
verse_text += verse
|
||||
verse_text += closing
|
||||
return verse_text
|
||||
|
||||
def reloadBibles(self):
|
||||
log.debug(u'Reloading Bibles')
|
||||
self.parent.biblemanager.reload_bibles()
|
||||
self.parent.manager.reload_bibles()
|
||||
self.loadBibles()
|
||||
|
||||
def initialiseBible(self, bible):
|
||||
log.debug(u'initialiseBible %s', bible)
|
||||
book_data = self.parent.biblemanager.get_bible_books()
|
||||
book_data = self.parent.manager.get_books(bible)
|
||||
self.AdvancedBookComboBox.clear()
|
||||
first = True
|
||||
for book in book_data:
|
||||
row = self.AdvancedBookComboBox.count()
|
||||
self.AdvancedBookComboBox.addItem(book[u'book'])
|
||||
self.AdvancedBookComboBox.addItem(book[u'name'])
|
||||
self.AdvancedBookComboBox.setItemData(
|
||||
row, QtCore.QVariant(book[u'total']))
|
||||
row, QtCore.QVariant(book[u'chapters']))
|
||||
if first:
|
||||
first = False
|
||||
self.initialiseChapterVerse(
|
||||
bible, book[u'book'], book[u'total'])
|
||||
bible, book[u'name'], book[u'chapters'])
|
||||
|
||||
def initialiseChapterVerse(self, bible, book, chapters):
|
||||
log.debug(u'initialiseChapterVerse %s, %s', bible, book)
|
||||
self.chapters_from = chapters
|
||||
self.verses = self.parent.biblemanager.get_book_verse_count(bible,
|
||||
book, 1)
|
||||
self.verses = self.parent.manager.get_verse_count(bible, book, 1)
|
||||
if self.verses == 0:
|
||||
self.AdvancedSearchButton.setEnabled(False)
|
||||
self.AdvancedMessage.setText(self.trUtf8('Bible not fully loaded'))
|
||||
|
@ -519,12 +556,30 @@ class BibleMediaItem(MediaManagerItem):
|
|||
combo.addItem(unicode(i))
|
||||
|
||||
def displayResults(self, bible):
|
||||
version = self.parent.manager.get_meta_data(bible, u'Version')
|
||||
copyright = self.parent.manager.get_meta_data(bible, u'Copyright')
|
||||
permission = self.parent.manager.get_meta_data(bible, u'Permission')
|
||||
if not permission:
|
||||
permission = u''
|
||||
else:
|
||||
permission = permission.value
|
||||
for count, verse in enumerate(self.search_results):
|
||||
bible_text = u' %s %d:%d (%s)' % (verse.book.name,
|
||||
verse.chapter, verse.verse, bible)
|
||||
bible_text = u' %s %d:%d (%s)' % \
|
||||
(verse.book.name, verse.chapter, verse.verse, bible)
|
||||
bible_verse = QtGui.QListWidgetItem(bible_text)
|
||||
bible_verse.setData(QtCore.Qt.UserRole,
|
||||
QtCore.QVariant(bible_text))
|
||||
#bible_verse.setData(QtCore.Qt.UserRole,
|
||||
# QtCore.QVariant(bible_text))
|
||||
vdict = {
|
||||
'bible': QtCore.QVariant(bible),
|
||||
'version': QtCore.QVariant(version.value),
|
||||
'copyright': QtCore.QVariant(copyright.value),
|
||||
'permission': QtCore.QVariant(permission),
|
||||
'book': QtCore.QVariant(verse.book.name),
|
||||
'chapter': QtCore.QVariant(verse.chapter),
|
||||
'verse': QtCore.QVariant(verse.verse),
|
||||
'text': QtCore.QVariant(verse.text)
|
||||
}
|
||||
bible_verse.setData(QtCore.Qt.UserRole, QtCore.QVariant(vdict))
|
||||
self.ListView.addItem(bible_verse)
|
||||
row = self.ListView.setCurrentRow(count)
|
||||
if row:
|
||||
|
@ -532,85 +587,4 @@ class BibleMediaItem(MediaManagerItem):
|
|||
|
||||
def searchByReference(self, bible, search):
|
||||
log.debug(u'searchByReference %s, %s', bible, search)
|
||||
book = u''
|
||||
start_chapter = u''
|
||||
end_chapter = u''
|
||||
start_verse = u''
|
||||
end_verse = u''
|
||||
search = search.replace(u' ', u' ').strip()
|
||||
#original = search
|
||||
message = None
|
||||
# Remove book beware 0 index arrays
|
||||
for i in range (len(search)-1, 0, - 1):
|
||||
if search[i] == u' ':
|
||||
book = search[:i]
|
||||
# remove book from string
|
||||
search = search[i:]
|
||||
break
|
||||
# allow V or v for verse instead of :
|
||||
search = search.replace(u'v', ':')
|
||||
search = search.replace(u'V', ':')
|
||||
search = search.strip()
|
||||
colon = search.find(u':')
|
||||
if colon == -1:
|
||||
# number : found
|
||||
i = search.rfind(u' ')
|
||||
if i == -1:
|
||||
chapter = u''
|
||||
else:
|
||||
chapter = search[i:len(search)]
|
||||
hyphen = chapter.find(u'-')
|
||||
if hyphen != -1:
|
||||
start_chapter= chapter[:hyphen]
|
||||
end_chapter= chapter[hyphen + 1:len(chapter)]
|
||||
else:
|
||||
start_chapter = chapter
|
||||
else:
|
||||
# more complex
|
||||
sp = search.split(u'-') #find first
|
||||
sp1 = sp[0].split(u':')
|
||||
if len(sp1) == 1:
|
||||
start_chapter = sp1[0]
|
||||
start_verse = 1
|
||||
else:
|
||||
start_chapter = sp1[0]
|
||||
start_verse = sp1[1]
|
||||
if len(sp)== 1:
|
||||
end_chapter = start_chapter
|
||||
end_verse = start_verse
|
||||
else:
|
||||
sp1 = sp[1].split(u':')
|
||||
if len(sp1) == 1:
|
||||
end_chapter = start_chapter
|
||||
end_verse = sp1[0]
|
||||
else:
|
||||
end_chapter = sp1[0]
|
||||
end_verse = sp1[1]
|
||||
if end_chapter == u'':
|
||||
end_chapter = start_chapter.rstrip()
|
||||
if start_verse == u'':
|
||||
if end_verse == u'':
|
||||
start_verse = 1
|
||||
else:
|
||||
start_verse = end_verse
|
||||
if end_verse == u'':
|
||||
end_verse = 99
|
||||
if start_chapter == u'':
|
||||
message = self.trUtf8('No chapter found for search criteria')
|
||||
log.debug(u'results = %s @ %s : %s @ %s : %s'% \
|
||||
(unicode(book), unicode(start_chapter), unicode(end_chapter),
|
||||
unicode(start_verse), unicode(end_verse)))
|
||||
if message is None:
|
||||
self.search_results = None
|
||||
self.search_results = self.parent.biblemanager.get_verse_text(
|
||||
bible, book, int(start_chapter), int(end_chapter),
|
||||
int(start_verse), int(end_verse))
|
||||
self.copyright = unicode(self.parent.biblemanager.get_meta_data(
|
||||
bible, u'Copyright').value)
|
||||
self.permissions = unicode(self.parent.biblemanager.get_meta_data(
|
||||
bible, u'Permissions').value)
|
||||
self.version = unicode(self.parent.biblemanager.get_meta_data(
|
||||
bible, u'Version').value)
|
||||
else:
|
||||
QtGui.QMessageBox.information(
|
||||
self, self.trUtf8('Information'), message)
|
||||
self.search_results = self.parent.manager.get_verses(bible, search)
|
||||
|
|
|
@ -50,7 +50,7 @@ class BibleMeta(BaseModel):
|
|||
pass
|
||||
|
||||
|
||||
class ONTestament(BaseModel):
|
||||
class Testament(BaseModel):
|
||||
"""
|
||||
Bible Testaments
|
||||
"""
|
||||
|
@ -101,8 +101,8 @@ verse_table = Table(u'verse', metadata,
|
|||
Column(u'text', types.UnicodeText, index=True),
|
||||
)
|
||||
mapper(BibleMeta, meta_table)
|
||||
mapper(ONTestament, testament_table,
|
||||
mapper(Testament, testament_table,
|
||||
properties={'books': relation(Book, backref='testament')})
|
||||
mapper(Book, book_table,
|
||||
properties={'verses': relation(Verse, backref='book')})
|
||||
mapper(Verse, verse_table)
|
||||
mapper(Verse, verse_table)
|
||||
|
|
|
@ -23,39 +23,31 @@
|
|||
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
||||
###############################################################################
|
||||
|
||||
import os
|
||||
import os.path
|
||||
import logging
|
||||
import chardet
|
||||
import codecs
|
||||
from lxml import objectify
|
||||
|
||||
from lxml import objectify
|
||||
from PyQt4 import QtCore
|
||||
|
||||
from openlp.core.lib import Receiver
|
||||
from db import BibleDB
|
||||
|
||||
class BibleOpenSongImpl():
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
class OpenSongBible(BibleDB):
|
||||
"""
|
||||
OSIS Bible format importer class.
|
||||
OpenSong Bible format importer class.
|
||||
"""
|
||||
global log
|
||||
log = logging.getLogger(__name__)
|
||||
log.info(u'BibleOpenSongImpl loaded')
|
||||
|
||||
def __init__(self, biblepath, bibledb):
|
||||
def __init__(self, parent, **kwargs):
|
||||
"""
|
||||
Constructor to create and set up an instance of the
|
||||
BibleOpenSongImpl class.
|
||||
|
||||
``biblepath``
|
||||
This does not seem to be used.
|
||||
|
||||
``bibledb``
|
||||
A reference to a Bible database object.
|
||||
Constructor to create and set up an instance of the OpenSongBible
|
||||
class. This class is used to import Bibles from OpenSong's XML format.
|
||||
"""
|
||||
log.info(u'BibleOpenSongImpl Initialising')
|
||||
self.bibledb = bibledb
|
||||
self.loadbible = True
|
||||
log.debug(__name__)
|
||||
BibleDB.__init__(self, parent, **kwargs)
|
||||
if 'filename' not in kwargs:
|
||||
raise KeyError(u'You have to supply a file name to import from.')
|
||||
self.filename = kwargs['filename']
|
||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||
QtCore.SIGNAL(u'openlpstopimport'), self.stop_import)
|
||||
|
||||
|
@ -63,64 +55,55 @@ class BibleOpenSongImpl():
|
|||
"""
|
||||
Stops the import of the Bible.
|
||||
"""
|
||||
self.loadbible = False
|
||||
log.debug('Stopping import!')
|
||||
self.stop_import_flag = True
|
||||
|
||||
def load_data(self, bible_file, dialogobject=None):
|
||||
def do_import(self):
|
||||
"""
|
||||
Loads a Bible from file.
|
||||
|
||||
``bible_file``
|
||||
The file to import from.
|
||||
|
||||
``dialogobject``
|
||||
The Import dialog, so that we can increase the counter on
|
||||
the progress bar.
|
||||
"""
|
||||
log.info(u'Load data for %s' % bible_file)
|
||||
bible_file = unicode(bible_file)
|
||||
detect_file = None
|
||||
try:
|
||||
detect_file = open(bible_file, u'r')
|
||||
details = chardet.detect(detect_file.read(2048))
|
||||
except:
|
||||
log.exception(u'Failed to detect OpenSong file encoding')
|
||||
return
|
||||
finally:
|
||||
if detect_file:
|
||||
detect_file.close()
|
||||
opensong_bible = None
|
||||
log.debug(u'Starting OpenSong import from "%s"' % self.filename)
|
||||
self.filename = unicode(self.filename, u'utf-8')
|
||||
self.wizard.incrementProgressBar(u'Preparing for import...')
|
||||
file = None
|
||||
success = True
|
||||
try:
|
||||
opensong_bible = codecs.open(bible_file, u'r', details['encoding'])
|
||||
opensong = objectify.parse(opensong_bible)
|
||||
# NOTE: We don't need to do any of the normal encoding detection
|
||||
# here, because lxml does it's own encoding detection, and the two
|
||||
# mechanisms together interfere with each other.
|
||||
file = open(self.filename, u'r')
|
||||
opensong = objectify.parse(file)
|
||||
bible = opensong.getroot()
|
||||
for book in bible.b:
|
||||
if not self.loadbible:
|
||||
if self.stop_import_flag:
|
||||
break
|
||||
dbbook = self.bibledb.create_book(book.attrib[u'n'],
|
||||
book.attrib[u'n'][:4])
|
||||
db_book = self.create_book(unicode(book.attrib[u'n']),
|
||||
unicode(book.attrib[u'n'][:4]))
|
||||
for chapter in book.c:
|
||||
if not self.loadbible:
|
||||
if self.stop_import_flag:
|
||||
break
|
||||
for verse in chapter.v:
|
||||
if not self.loadbible:
|
||||
if self.stop_import_flag:
|
||||
break
|
||||
self.bibledb.add_verse(dbbook.id, chapter.attrib[u'n'],
|
||||
verse.attrib[u'n'], verse.text)
|
||||
self.create_verse(
|
||||
db_book.id,
|
||||
int(chapter.attrib[u'n']),
|
||||
int(verse.attrib[u'n']),
|
||||
unicode(verse.text)
|
||||
)
|
||||
Receiver.send_message(u'process_events')
|
||||
dialogobject.incrementProgressBar(u'Importing %s %s' % \
|
||||
(dbbook.name, str(chapter.attrib[u'n'])))
|
||||
self.bibledb.save_verses()
|
||||
self.wizard.incrementProgressBar(
|
||||
QtCore.QString('%s %s %s' % (self.trUtf8('Importing'),\
|
||||
db_book.name, chapter.attrib[u'n'])))
|
||||
self.commit()
|
||||
except:
|
||||
log.exception(u'Loading bible from OpenSong file failed')
|
||||
success = False
|
||||
finally:
|
||||
if opensong_bible:
|
||||
opensong_bible.close()
|
||||
if not self.loadbible:
|
||||
dialogobject.incrementProgressBar(u'Import canceled!')
|
||||
dialogobject.ImportProgressBar.setValue(
|
||||
dialogobject.ImportProgressBar.maximum())
|
||||
if file:
|
||||
file.close()
|
||||
if self.stop_import:
|
||||
self.wizard.incrementProgressBar(u'Import canceled!')
|
||||
return False
|
||||
else:
|
||||
return success
|
|
@ -33,27 +33,26 @@ import re
|
|||
from PyQt4 import QtCore
|
||||
|
||||
from openlp.core.lib import Receiver
|
||||
from db import BibleDB
|
||||
|
||||
class BibleOSISImpl():
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
class OSISBible(BibleDB):
|
||||
"""
|
||||
OSIS Bible format importer class.
|
||||
"""
|
||||
global log
|
||||
log = logging.getLogger(u'BibleOSISImpl')
|
||||
log.info(u'BibleOSISImpl loaded')
|
||||
|
||||
def __init__(self, biblepath, bibledb):
|
||||
def __init__(self, parent, **kwargs):
|
||||
"""
|
||||
Constructor to create and set up an instance of the
|
||||
BibleOSISImpl class.
|
||||
|
||||
``biblepath``
|
||||
This does not seem to be used.
|
||||
|
||||
``bibledb``
|
||||
A reference to a Bible database object.
|
||||
Constructor to create and set up an instance of the OpenSongBible
|
||||
class. This class is used to import Bibles from OpenSong's XML format.
|
||||
"""
|
||||
log.info(u'BibleOSISImpl Initialising')
|
||||
log.debug(__name__)
|
||||
BibleDB.__init__(self, parent, **kwargs)
|
||||
if u'filename' not in kwargs:
|
||||
raise KeyError(u'You have to supply a file name to import from.')
|
||||
self.filename = kwargs[u'filename']
|
||||
self.verse_regex = re.compile(
|
||||
r'<verse osisID="([a-zA-Z0-9 ]*).([0-9]*).([0-9]*)">(.*?)</verse>')
|
||||
self.note_regex = re.compile(r'<note(.*?)>(.*?)</note>')
|
||||
|
@ -66,13 +65,11 @@ class BibleOSISImpl():
|
|||
self.w_regex = re.compile(r'<w (.*?)>')
|
||||
self.q_regex = re.compile(r'<q (.*?)>')
|
||||
self.spaces_regex = re.compile(r'([ ]{2,})')
|
||||
self.bibledb = bibledb
|
||||
self.books = {}
|
||||
filepath = os.path.split(os.path.abspath(__file__))[0]
|
||||
filepath = os.path.abspath(os.path.join(
|
||||
filepath, u'..', u'resources', u'osisbooks.csv'))
|
||||
fbibles = None
|
||||
self.loadbible = True
|
||||
try:
|
||||
fbibles = open(filepath, u'r')
|
||||
for line in fbibles:
|
||||
|
@ -92,24 +89,18 @@ class BibleOSISImpl():
|
|||
Stops the import of the Bible.
|
||||
"""
|
||||
log.debug('Stopping import!')
|
||||
self.loadbible = False
|
||||
self.stop_import_flag = True
|
||||
|
||||
def load_data(self, osisfile_record, dialogobject=None):
|
||||
def do_import(self):
|
||||
"""
|
||||
Loads a Bible from file.
|
||||
|
||||
``osisfile_record``
|
||||
The file to import from.
|
||||
|
||||
``dialogobject``
|
||||
The Import dialog, so that we can increase the counter on
|
||||
the progress bar.
|
||||
"""
|
||||
log.info(u'Load data for %s' % osisfile_record)
|
||||
log.debug(u'Starting OSIS import from "%s"' % self.filename)
|
||||
self.wizard.incrementProgressBar(u'Detecting encoding (this may take a few minutes)...')
|
||||
detect_file = None
|
||||
try:
|
||||
detect_file = open(osisfile_record, u'r')
|
||||
details = chardet.detect(detect_file.read(3000))
|
||||
detect_file = open(self.filename, u'r')
|
||||
details = chardet.detect(detect_file.read())
|
||||
except:
|
||||
log.exception(u'Failed to detect OSIS file encoding')
|
||||
return
|
||||
|
@ -119,12 +110,12 @@ class BibleOSISImpl():
|
|||
osis = None
|
||||
success = True
|
||||
try:
|
||||
osis = codecs.open(osisfile_record, u'r', details['encoding'])
|
||||
osis = codecs.open(self.filename, u'r', details['encoding'])
|
||||
last_chapter = 0
|
||||
testament = 1
|
||||
db_book = None
|
||||
for file_record in osis:
|
||||
if not self.loadbible:
|
||||
if self.stop_import_flag:
|
||||
break
|
||||
match = self.verse_regex.search(file_record)
|
||||
if match:
|
||||
|
@ -136,19 +127,19 @@ class BibleOSISImpl():
|
|||
log.debug('New book: "%s"', self.books[book][0])
|
||||
if book == u'Matt':
|
||||
testament += 1
|
||||
db_book = self.bibledb.create_book(
|
||||
db_book = self.create_book(
|
||||
unicode(self.books[book][0]),
|
||||
unicode(self.books[book][1]),
|
||||
testament)
|
||||
if last_chapter == 0:
|
||||
if book == u'Gen':
|
||||
dialogobject.ImportProgressBar.setMaximum(1188)
|
||||
self.wizard.ImportProgressBar.setMaximum(1188)
|
||||
else:
|
||||
dialogobject.ImportProgressBar.setMaximum(260)
|
||||
self.wizard.ImportProgressBar.setMaximum(260)
|
||||
if last_chapter != chapter:
|
||||
if last_chapter != 0:
|
||||
self.bibledb.save_verses()
|
||||
dialogobject.incrementProgressBar(
|
||||
self.commit()
|
||||
self.wizard.incrementProgressBar(
|
||||
u'Importing %s %s...' % \
|
||||
(self.books[match.group(1)][0], chapter))
|
||||
last_chapter = chapter
|
||||
|
@ -170,20 +161,18 @@ class BibleOSISImpl():
|
|||
.replace(u'</lg>', u'').replace(u'</q>', u'')\
|
||||
.replace(u'</div>', u'')
|
||||
verse_text = self.spaces_regex.sub(u' ', verse_text)
|
||||
self.bibledb.add_verse(db_book.id, chapter, verse, verse_text)
|
||||
self.create_verse(db_book.id, chapter, verse, verse_text)
|
||||
Receiver.send_message(u'process_events')
|
||||
self.bibledb.save_verses()
|
||||
dialogobject.incrementProgressBar(u'Finishing import...')
|
||||
self.commit()
|
||||
self.wizard.incrementProgressBar(u'Finishing import...')
|
||||
except:
|
||||
log.exception(u'Loading bible from OSIS file failed')
|
||||
success = False
|
||||
finally:
|
||||
if osis:
|
||||
osis.close()
|
||||
if not self.loadbible:
|
||||
dialogobject.incrementProgressBar(u'Import canceled!')
|
||||
dialogobject.ImportProgressBar.setValue(
|
||||
dialogobject.ImportProgressBar.maximum())
|
||||
if self.stop_import_flag:
|
||||
self.wizard.incrementProgressBar(u'Import canceled!')
|
||||
return False
|
||||
else:
|
||||
return success
|
||||
return success
|
|
@ -1,66 +0,0 @@
|
|||
Genesis,Gen,1,50
|
||||
Exodus,Exod,1,40
|
||||
Leviticus,Lev,1,27
|
||||
Numbers,Num,1,36
|
||||
Deuteronomy,Deut,1,34
|
||||
Joshua,Josh,1,24
|
||||
Judges,Judg,1,21
|
||||
Ruth,Ruth,1,4
|
||||
1 Samual,1Sam,1,31
|
||||
2 Samual,2Sam,1,24
|
||||
1 Kings,1Kgs,1,22
|
||||
2 Kings,2Kgs,1,25
|
||||
1 Chronicles,1Chr,1,29
|
||||
2 Chronicles,2Chr,1,36
|
||||
Ezra,Esra,1,10
|
||||
Nehemiah,Neh,1,13
|
||||
Esther,Esth,1,10
|
||||
Job,Job,1,42
|
||||
Psalms,Ps,1,150
|
||||
Proverbs,Prov,1,31
|
||||
Ecclesiastes,Eccl,1,12
|
||||
Song of Songs,Song,1,8
|
||||
Isaiah,Isa,1,66
|
||||
Jeremiah,Jer,1,5
|
||||
Lamentations,Lam,1,5
|
||||
Ezekiel,Ezek,1,48
|
||||
Daniel,Dan,1,12
|
||||
Hosea,Hos,1,14
|
||||
Joel,Joel,1,3
|
||||
Amos,Amos,1,9
|
||||
Obad,Obad,1,1
|
||||
Jonah,Jonah,1,4
|
||||
Micah,Mic,1,7
|
||||
Naham,Nah,1,3
|
||||
Habakkuk,Hab,1,3
|
||||
Zephaniah,Zeph,1,3
|
||||
Haggai,Hag,1,2
|
||||
Zechariah,Zech,1,3
|
||||
Malachi,Mal,1,4
|
||||
Matthew,Matt,2,28
|
||||
Mark,Mark,2,16
|
||||
Luke,Luke,2,24
|
||||
John,John,2,21
|
||||
Acts,Acts,2,28
|
||||
Romans,Rom,2,16
|
||||
1 Corinthans,1Cor,2,16
|
||||
2 Corinthans,2Cor,2,13
|
||||
Galatians,Gal,2,6
|
||||
Ephesians,Eph,2,6
|
||||
Philippians,Phil,2,4
|
||||
Colossians,Col,2,4
|
||||
1 Thessalonians,1Thess,2,5
|
||||
2 Thessalonians,2Thess,2,3
|
||||
1 Timothy,1Tim,2,6
|
||||
2 Timothy,2Tim,2,4
|
||||
Titus,Titus,2,3
|
||||
Philemon,Phlm,2,1
|
||||
Hebrews,Heb,2,13
|
||||
James,Jas,2,5
|
||||
1 Peter,1Pet,2,5
|
||||
2 Peter,2Pet,2,3
|
||||
1 John,1John,2,5
|
||||
2 John,2John,2,1
|
||||
3 John,3John,2,1
|
||||
Jude,Jude,2,1
|
||||
Revelation,Rev,2,22
|
|
Binary file not shown.
|
@ -26,9 +26,10 @@
|
|||
import logging
|
||||
|
||||
from forms import EditCustomForm
|
||||
from openlp.core.lib import Plugin, build_icon
|
||||
from openlp.core.lib import Plugin, build_icon, PluginStatus
|
||||
from openlp.plugins.custom.lib import CustomManager, CustomMediaItem, CustomTab
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
class CustomPlugin(Plugin):
|
||||
"""
|
||||
|
@ -39,17 +40,15 @@ class CustomPlugin(Plugin):
|
|||
the songs plugin has become restrictive. Examples could be
|
||||
Welcome slides, Bible Reading information, Orders of service.
|
||||
"""
|
||||
|
||||
global log
|
||||
log = logging.getLogger(u'CustomPlugin')
|
||||
log.info(u'Custom Plugin loaded')
|
||||
|
||||
def __init__(self, plugin_helpers):
|
||||
Plugin.__init__(self, u'Custom', u'1.9.0', plugin_helpers)
|
||||
Plugin.__init__(self, u'Custom', u'1.9.1', plugin_helpers)
|
||||
self.weight = -5
|
||||
self.custommanager = CustomManager(self.config)
|
||||
self.edit_custom_form = EditCustomForm(self.custommanager)
|
||||
self.icon = build_icon(u':/media/media_custom.png')
|
||||
self.status = PluginStatus.Active
|
||||
|
||||
def get_settings_tab(self):
|
||||
return CustomTab(self.name)
|
||||
|
@ -72,4 +71,9 @@ class CustomPlugin(Plugin):
|
|||
'allows slides to be displayed on the screen in the same way '
|
||||
'songs are. This plugin provides greater freedom over the '
|
||||
'songs plugin.<br>')
|
||||
return about_text
|
||||
return about_text
|
||||
|
||||
def can_delete_theme(self, theme):
|
||||
if len(self.custommanager.get_customs_for_theme(theme)) == 0:
|
||||
return True
|
||||
return False
|
||||
|
|
|
@ -30,12 +30,12 @@ from editcustomdialog import Ui_customEditDialog
|
|||
from openlp.core.lib import SongXMLBuilder, SongXMLParser, Receiver
|
||||
from openlp.plugins.custom.lib.models import CustomSlide
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
class EditCustomForm(QtGui.QDialog, Ui_customEditDialog):
|
||||
"""
|
||||
Class documentation goes here.
|
||||
"""
|
||||
global log
|
||||
log = logging.getLogger(u'EditCustomForm')
|
||||
log.info(u'Custom Editor loaded')
|
||||
def __init__(self, custommanager, parent = None):
|
||||
"""
|
||||
|
@ -153,10 +153,10 @@ class EditCustomForm(QtGui.QDialog, Ui_customEditDialog):
|
|||
sxml.add_verse_to_lyrics(u'custom', unicode(count),
|
||||
unicode(self.VerseListView.item(i).text()))
|
||||
count += 1
|
||||
self.customSlide.title = unicode(self.TitleEdit.displayText())
|
||||
self.customSlide.text = unicode(sxml.extract_xml())
|
||||
self.customSlide.credits = unicode(self.CreditEdit.displayText())
|
||||
self.customSlide.theme_name = unicode(self.ThemeComboBox.currentText())
|
||||
self.customSlide.title = unicode(self.TitleEdit.displayText(), u'utf-8')
|
||||
self.customSlide.text = unicode(sxml.extract_xml(), u'utf-8')
|
||||
self.customSlide.credits = unicode(self.CreditEdit.displayText(), u'utf-8')
|
||||
self.customSlide.theme_name = unicode(self.ThemeComboBox.currentText(), u'utf-8')
|
||||
self.custommanager.save_slide(self.customSlide)
|
||||
return True
|
||||
|
||||
|
@ -254,7 +254,7 @@ class EditCustomForm(QtGui.QDialog, Ui_customEditDialog):
|
|||
if self.VerseListView.count() == 0:
|
||||
self.VerseTextEdit.setFocus()
|
||||
return False, self.trUtf8('You need to enter a slide')
|
||||
if len(self.VerseTextEdit.toPlainText()) > 0:
|
||||
if self.VerseTextEdit.toPlainText():
|
||||
self.VerseTextEdit.setFocus()
|
||||
return False, self.trUtf8('You have unsaved data')
|
||||
return True, u''
|
||||
return True, u''
|
||||
|
|
|
@ -27,14 +27,13 @@ import logging
|
|||
|
||||
from openlp.plugins.custom.lib.models import init_models, metadata, CustomSlide
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
class CustomManager():
|
||||
"""
|
||||
The Song Manager provides a central location for all database code. This
|
||||
class takes care of connecting to the database and running all the queries.
|
||||
"""
|
||||
|
||||
global log
|
||||
log = logging.getLogger(u'CustomManager')
|
||||
log.info(u'Custom manager loaded')
|
||||
|
||||
def __init__(self, config):
|
||||
|
@ -78,7 +77,7 @@ class CustomManager():
|
|||
return True
|
||||
except:
|
||||
self.session.rollback()
|
||||
log.excertion(u'Custom Slide save failed')
|
||||
log.exception(u'Custom Slide save failed')
|
||||
return False
|
||||
|
||||
def get_custom(self, id=None):
|
||||
|
@ -94,7 +93,7 @@ class CustomManager():
|
|||
"""
|
||||
Delete a Custom slide show
|
||||
"""
|
||||
if id !=0:
|
||||
if id != 0:
|
||||
customslide = self.get_custom(id)
|
||||
try:
|
||||
self.session.delete(customslide)
|
||||
|
@ -102,7 +101,10 @@ class CustomManager():
|
|||
return True
|
||||
except:
|
||||
self.session.rollback()
|
||||
log.excertion(u'Custom Slide deleton failed')
|
||||
log.exception(u'Custom Slide deleton failed')
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
return True
|
||||
|
||||
def get_customs_for_theme(self, theme):
|
||||
return self.session.query(CustomSlide).filter(CustomSlide.theme_name == theme).all()
|
||||
|
|
|
@ -30,6 +30,8 @@ from PyQt4 import QtCore, QtGui
|
|||
from openlp.core.lib import MediaManagerItem, SongXMLParser, BaseListWithDnD,\
|
||||
Receiver, str_to_bool
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
class CustomListView(BaseListWithDnD):
|
||||
def __init__(self, parent=None):
|
||||
self.PluginName = u'Custom'
|
||||
|
@ -39,8 +41,6 @@ class CustomMediaItem(MediaManagerItem):
|
|||
"""
|
||||
This is the custom media manager item for Custom Slides.
|
||||
"""
|
||||
global log
|
||||
log = logging.getLogger(u'CustomMediaItem')
|
||||
log.info(u'Custom Media Item loaded')
|
||||
|
||||
def __init__(self, parent, icon, title):
|
||||
|
@ -144,13 +144,14 @@ class CustomMediaItem(MediaManagerItem):
|
|||
item_id = (item.data(QtCore.Qt.UserRole)).toInt()[0]
|
||||
else:
|
||||
item_id = self.remoteCustom
|
||||
service_item.autoPreviewAllowed = True
|
||||
customSlide = self.parent.custommanager.get_custom(item_id)
|
||||
title = customSlide.title
|
||||
credit = customSlide.credits
|
||||
service_item.edit_enabled = True
|
||||
service_item.editId = item_id
|
||||
theme = customSlide.theme_name
|
||||
if len(theme) is not 0 :
|
||||
if theme:
|
||||
service_item.theme = theme
|
||||
songXML = SongXMLParser(customSlide.text)
|
||||
verseList = songXML.get_verses()
|
||||
|
@ -159,10 +160,10 @@ class CustomMediaItem(MediaManagerItem):
|
|||
service_item.title = title
|
||||
for slide in raw_slides:
|
||||
service_item.add_from_text(slide[:30], slide)
|
||||
if str_to_bool(self.parent.config.get_config(u'display footer', True)) or \
|
||||
len(credit) > 0:
|
||||
raw_footer.append(title + u' '+ credit)
|
||||
if str_to_bool(self.parent.config.get_config(u'display footer', True)) \
|
||||
or credit:
|
||||
raw_footer.append(title + u' ' + credit)
|
||||
else:
|
||||
raw_footer.append(u'')
|
||||
service_item.raw_footer = raw_footer
|
||||
return True
|
||||
return True
|
||||
|
|
|
@ -27,11 +27,11 @@ from sqlalchemy import Column, Table, types
|
|||
|
||||
from openlp.plugins.custom.lib.meta import metadata
|
||||
|
||||
# Definition of the "songs" table
|
||||
# Definition of the "custom slide" table
|
||||
custom_slide_table = Table(u'custom_slide', metadata,
|
||||
Column(u'id', types.Integer(), primary_key=True),
|
||||
Column(u'title', types.Unicode(255), nullable=False),
|
||||
Column(u'text', types.UnicodeText, nullable=False),
|
||||
Column(u'credits', types.UnicodeText),
|
||||
Column(u'theme_name', types.Unicode(128))
|
||||
)
|
||||
)
|
||||
|
|
|
@ -25,18 +25,19 @@
|
|||
|
||||
import logging
|
||||
|
||||
from openlp.core.lib import Plugin, build_icon
|
||||
from openlp.core.lib import Plugin, build_icon, PluginStatus
|
||||
from openlp.plugins.images.lib import ImageMediaItem, ImageTab
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
class ImagePlugin(Plugin):
|
||||
global log
|
||||
log = logging.getLogger(u'ImagePlugin')
|
||||
log.info(u'Image Plugin loaded')
|
||||
|
||||
def __init__(self, plugin_helpers):
|
||||
Plugin.__init__(self, u'Images', u'1.9.0', plugin_helpers)
|
||||
Plugin.__init__(self, u'Images', u'1.9.1', plugin_helpers)
|
||||
self.weight = -7
|
||||
self.icon = build_icon(u':/media/media_image.png')
|
||||
self.status = PluginStatus.Active
|
||||
|
||||
def initialise(self):
|
||||
log.info(u'Plugin Initialising')
|
||||
|
@ -60,6 +61,6 @@ class ImagePlugin(Plugin):
|
|||
'together and presented on the live controller it is possible '
|
||||
'to turn them into a timed loop.<br<br>From the plugin if the '
|
||||
'<i>Override background</i> is chosen and an image is selected '
|
||||
'any somgs which are rendered will use the selected image from '
|
||||
'any songs which are rendered will use the selected image from '
|
||||
'the background instead of the one provied by the theme.<br>')
|
||||
return about_text
|
||||
return about_text
|
||||
|
|
|
@ -49,6 +49,7 @@ class ImageTab(SettingsTab):
|
|||
self.TimeoutLabel.setObjectName(u'TimeoutLabel')
|
||||
self.TimeoutLayout.addWidget(self.TimeoutLabel)
|
||||
self.TimeoutSpinBox = QtGui.QSpinBox(self.ImageSettingsGroupBox)
|
||||
self.TimeoutSpinBox.setMinimum(1)
|
||||
self.TimeoutSpinBox.setMaximum(180)
|
||||
self.TimeoutSpinBox.setObjectName(u'TimeoutSpinBox')
|
||||
self.TimeoutLayout.addWidget(self.TimeoutSpinBox)
|
||||
|
@ -78,4 +79,4 @@ class ImageTab(SettingsTab):
|
|||
Receiver.send_message(u'update_spin_delay', self.loop_delay)
|
||||
|
||||
def postSetUp(self):
|
||||
Receiver.send_message(u'update_spin_delay', self.loop_delay)
|
||||
Receiver.send_message(u'update_spin_delay', self.loop_delay)
|
||||
|
|
|
@ -29,6 +29,8 @@ import os
|
|||
from PyQt4 import QtCore, QtGui
|
||||
from openlp.core.lib import MediaManagerItem, BaseListWithDnD, build_icon
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
# We have to explicitly create separate classes for each plugin
|
||||
# in order for DnD to the Service manager to work correctly.
|
||||
class ImageListView(BaseListWithDnD):
|
||||
|
@ -40,8 +42,6 @@ class ImageMediaItem(MediaManagerItem):
|
|||
"""
|
||||
This is the custom media manager item for images.
|
||||
"""
|
||||
global log
|
||||
log = logging.getLogger(u'ImageMediaItem')
|
||||
log.info(u'Image Media Item loaded')
|
||||
|
||||
def __init__(self, parent, icon, title):
|
||||
|
@ -61,7 +61,7 @@ class ImageMediaItem(MediaManagerItem):
|
|||
def retranslateUi(self):
|
||||
self.OnNewPrompt = self.trUtf8('Select Image(s)')
|
||||
self.OnNewFileMasks = \
|
||||
self.trUtf8('Images (*.jpg *jpeg *.gif *.png *.bmp)')
|
||||
self.trUtf8('Images (*.jpg *jpeg *.gif *.png *.bmp);; All files (*)')
|
||||
|
||||
def requiredIcons(self):
|
||||
MediaManagerItem.requiredIcons(self)
|
||||
|
@ -144,6 +144,7 @@ class ImageMediaItem(MediaManagerItem):
|
|||
items = self.ListView.selectedIndexes()
|
||||
if items:
|
||||
service_item.title = self.trUtf8('Image(s)')
|
||||
service_item.autoPreviewAllowed = True
|
||||
for item in items:
|
||||
bitem = self.ListView.item(item.row())
|
||||
filename = unicode((bitem.data(QtCore.Qt.UserRole)).toString())
|
||||
|
@ -172,7 +173,6 @@ class ImageMediaItem(MediaManagerItem):
|
|||
filename = unicode((bitem.data(QtCore.Qt.UserRole)).toString())
|
||||
self.OverrideLabel.setText(bitem.text())
|
||||
frame = QtGui.QImage(unicode(filename))
|
||||
self.parent.render_manager.override_background = frame
|
||||
self.parent.render_manager.override_background_changed = True
|
||||
self.parent.maindisplay.addImageWithText(frame)
|
||||
else:
|
||||
MediaManagerItem.onPreviewClick(self)
|
||||
MediaManagerItem.onPreviewClick(self)
|
||||
|
|
|
@ -30,6 +30,8 @@ from PyQt4 import QtCore, QtGui
|
|||
|
||||
from openlp.core.lib import MediaManagerItem, BaseListWithDnD, build_icon
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
class MediaListView(BaseListWithDnD):
|
||||
def __init__(self, parent=None):
|
||||
self.PluginName = u'Media'
|
||||
|
@ -39,9 +41,7 @@ class MediaMediaItem(MediaManagerItem):
|
|||
"""
|
||||
This is the custom media manager item for Media Slides.
|
||||
"""
|
||||
global log
|
||||
log = logging.getLogger(u'MediaMediaItem')
|
||||
log.info(u'Media Media Item loaded')
|
||||
log.info(u'%s MediaMediaItem loaded', __name__)
|
||||
|
||||
def __init__(self, parent, icon, title):
|
||||
self.PluginNameShort = u'Media'
|
||||
|
@ -54,15 +54,16 @@ class MediaMediaItem(MediaManagerItem):
|
|||
self.PreviewFunction = self.video_get_preview
|
||||
MediaManagerItem.__init__(self, parent, icon, title)
|
||||
self.ServiceItemIconName = u':/media/media_video.png'
|
||||
self.MainDisplay = self.parent.live_controller.parent.mainDisplay
|
||||
self.MainDisplay = self.parent.maindisplay
|
||||
|
||||
def initPluginNameVisible(self):
|
||||
self.PluginNameVisible = self.trUtf8('Media')
|
||||
|
||||
def retranslateUi(self):
|
||||
self.OnNewPrompt = self.trUtf8('Select Media')
|
||||
self.OnNewFileMasks = self.trUtf8('Videos (*.avi *.mpeg *.mpg'
|
||||
'*.mp4);;Audio (*.ogg *.mp3 *.wma);;All files (*)')
|
||||
self.OnNewFileMasks = self.trUtf8('Videos (%s);;'
|
||||
'Audio (%s);;'
|
||||
'All files (*)' % (self.parent.video_list, self.parent.audio_list))
|
||||
|
||||
def requiredIcons(self):
|
||||
MediaManagerItem.requiredIcons(self)
|
||||
|
@ -84,7 +85,7 @@ class MediaMediaItem(MediaManagerItem):
|
|||
for item in items:
|
||||
bitem = self.ListView.item(item.row())
|
||||
filename = unicode((bitem.data(QtCore.Qt.UserRole)).toString())
|
||||
frame = u':/media/media_video.png'
|
||||
frame = u':/media/image_clapperboard.png'
|
||||
(path, name) = os.path.split(filename)
|
||||
service_item.add_from_command(path, name, frame)
|
||||
return True
|
||||
|
@ -110,4 +111,4 @@ class MediaMediaItem(MediaManagerItem):
|
|||
img = self.video_get_preview()
|
||||
item_name.setIcon(build_icon(img))
|
||||
item_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(file))
|
||||
self.ListView.addItem(item_name)
|
||||
self.ListView.addItem(item_name)
|
||||
|
|
|
@ -25,20 +25,41 @@
|
|||
|
||||
import logging
|
||||
|
||||
from openlp.core.lib import Plugin, build_icon
|
||||
from openlp.core.lib import Plugin, build_icon, PluginStatus
|
||||
from openlp.plugins.media.lib import MediaMediaItem
|
||||
from PyQt4.phonon import Phonon
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
class MediaPlugin(Plugin):
|
||||
global log
|
||||
log = logging.getLogger(u'MediaPlugin')
|
||||
log.info(u'Media Plugin loaded')
|
||||
log.info(u'%s MediaPlugin loaded', __name__)
|
||||
|
||||
def __init__(self, plugin_helpers):
|
||||
Plugin.__init__(self, u'Media', u'1.9.0', plugin_helpers)
|
||||
Plugin.__init__(self, u'Media', u'1.9.1', plugin_helpers)
|
||||
self.weight = -6
|
||||
self.icon = build_icon(u':/media/media_video.png')
|
||||
# passed with drag and drop messages
|
||||
self.dnd_id = u'Media'
|
||||
self.status = PluginStatus.Active
|
||||
self.audio_list = u''
|
||||
self.video_list = u''
|
||||
for mimetype in Phonon.BackendCapabilities.availableMimeTypes():
|
||||
mimetype = unicode(mimetype)
|
||||
type = mimetype.split(u'audio/x-')
|
||||
self.audio_list, mimetype = self._add_to_list(self.audio_list, type, mimetype)
|
||||
type = mimetype.split(u'audio/')
|
||||
self.audio_list, mimetype = self._add_to_list(self.audio_list, type, mimetype)
|
||||
type = mimetype.split(u'video/x-')
|
||||
self.video_list, mimetype = self._add_to_list(self.video_list, type, mimetype)
|
||||
type = mimetype.split(u'video/')
|
||||
self.video_list, mimetype = self._add_to_list(self.video_list, type, mimetype)
|
||||
|
||||
def _add_to_list(self, list, value, type):
|
||||
if len(value) == 2:
|
||||
if list.find(value[1]) == -1:
|
||||
list += u'*.%s ' % value[1]
|
||||
type = u''
|
||||
return list, type
|
||||
|
||||
def initialise(self):
|
||||
log.info(u'Plugin Initialising')
|
||||
|
@ -56,4 +77,4 @@ class MediaPlugin(Plugin):
|
|||
def about(self):
|
||||
about_text = self.trUtf8('<b>Media Plugin</b><br>This plugin '
|
||||
'allows the playing of audio and video media')
|
||||
return about_text
|
||||
return about_text
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
# OOo API documentation:
|
||||
# http://api.openoffice.org/docs/common/ref/com/sun/star/presentation/XSlideShowController.html
|
||||
# http://wiki.services.openoffice.org/wiki/Documentation/DevGuide/ProUNO/Basic/Getting_Information_about_UNO_Objects#Inspecting_interfaces_during_debugging
|
||||
# http://docs.go-oo.org/sd/html/classsd_1_1SlideShow.html
|
||||
# http://www.oooforum.org/forum/viewtopic.phtml?t=5252
|
||||
# http://wiki.services.openoffice.org/wiki/Documentation/DevGuide/Working_with_Presentations
|
||||
|
@ -44,7 +45,9 @@ else:
|
|||
|
||||
from PyQt4 import QtCore
|
||||
|
||||
from presentationcontroller import PresentationController
|
||||
from presentationcontroller import PresentationController, PresentationDocument
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
class ImpressController(PresentationController):
|
||||
"""
|
||||
|
@ -52,9 +55,7 @@ class ImpressController(PresentationController):
|
|||
It creates the runtime environment, loads and closes the presentation as
|
||||
well as triggering the correct activities based on the users input
|
||||
"""
|
||||
global log
|
||||
log = logging.getLogger(u'ImpressController')
|
||||
log.info(u'loaded')
|
||||
log.info(u'ImpressController loaded')
|
||||
|
||||
def __init__(self, plugin):
|
||||
"""
|
||||
|
@ -62,10 +63,10 @@ class ImpressController(PresentationController):
|
|||
"""
|
||||
log.debug(u'Initialising')
|
||||
PresentationController.__init__(self, plugin, u'Impress')
|
||||
self.supports = [u'.odp']
|
||||
self.alsosupports = [u'.ppt', u'.pps', u'.pptx', u'.ppsx']
|
||||
self.process = None
|
||||
self.document = None
|
||||
self.presentation = None
|
||||
self.controller = None
|
||||
self.desktop = None
|
||||
|
||||
def check_available(self):
|
||||
"""
|
||||
|
@ -85,7 +86,7 @@ class ImpressController(PresentationController):
|
|||
It is not displayed to the user but is available to the UNO interface
|
||||
when required.
|
||||
"""
|
||||
log.debug(u'start Openoffice')
|
||||
log.debug(u'start process Openoffice')
|
||||
if os.name == u'nt':
|
||||
self.manager = self.get_com_servicemanager()
|
||||
self.manager._FlagAsMethod(u'Bridge_GetStruct')
|
||||
|
@ -97,20 +98,88 @@ class ImpressController(PresentationController):
|
|||
self.process.startDetached(cmd)
|
||||
self.process.waitForStarted()
|
||||
|
||||
def get_uno_desktop(self):
|
||||
log.debug(u'get UNO Desktop Openoffice')
|
||||
ctx = None
|
||||
loop = 0
|
||||
log.debug(u'get UNO Desktop Openoffice - getComponentContext')
|
||||
context = uno.getComponentContext()
|
||||
log.debug(u'get UNO Desktop Openoffice - createInstaneWithContext - UnoUrlResolver')
|
||||
resolver = context.ServiceManager.createInstanceWithContext(
|
||||
u'com.sun.star.bridge.UnoUrlResolver', context)
|
||||
while ctx is None and loop < 3:
|
||||
try:
|
||||
log.debug(u'get UNO Desktop Openoffice - resolve')
|
||||
ctx = resolver.resolve(u'uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext')
|
||||
except:
|
||||
log.exception(u'Unable to find running instance ')
|
||||
self.start_process()
|
||||
loop += 1
|
||||
try:
|
||||
self.manager = ctx.ServiceManager
|
||||
log.debug(u'get UNO Desktop Openoffice - createInstanceWithContext - Desktop')
|
||||
desktop = self.manager.createInstanceWithContext(
|
||||
"com.sun.star.frame.Desktop", ctx )
|
||||
return desktop
|
||||
except:
|
||||
log.exception(u'Failed to get UNO desktop')
|
||||
return None
|
||||
|
||||
def get_com_desktop(self):
|
||||
log.debug(u'get COM Desktop OpenOffice')
|
||||
try:
|
||||
desktop = self.manager.createInstance(u'com.sun.star.frame.Desktop')
|
||||
return desktop
|
||||
except:
|
||||
log.exception(u'Failed to get COM desktop')
|
||||
return None
|
||||
|
||||
def get_com_servicemanager(self):
|
||||
log.debug(u'get_com_servicemanager openoffice')
|
||||
try:
|
||||
return Dispatch(u'com.sun.star.ServiceManager')
|
||||
except:
|
||||
log.exception(u'Failed to get COM service manager')
|
||||
return None
|
||||
|
||||
def kill(self):
|
||||
"""
|
||||
Called at system exit to clean up any running presentations
|
||||
"""
|
||||
log.debug(u'Kill')
|
||||
self.close_presentation()
|
||||
log.debug(u'Kill OpenOffice')
|
||||
for doc in self.docs:
|
||||
doc.close_presentation()
|
||||
if os.name != u'nt':
|
||||
desktop = self.get_uno_desktop()
|
||||
else:
|
||||
desktop = self.get_com_desktop()
|
||||
docs = desktop.getComponents()
|
||||
if docs.hasElements():
|
||||
log.debug(u'OpenOffice not terminated')
|
||||
else:
|
||||
try:
|
||||
desktop.terminate()
|
||||
log.debug(u'OpenOffice killed')
|
||||
except:
|
||||
pass
|
||||
log.exception(u'Failed to terminate OpenOffice')
|
||||
|
||||
def load_presentation(self, presentation):
|
||||
def add_doc(self, name):
|
||||
log.debug(u'Add Doc OpenOffice')
|
||||
doc = ImpressDocument(self, name)
|
||||
self.docs.append(doc)
|
||||
return doc
|
||||
|
||||
class ImpressDocument(PresentationDocument):
|
||||
|
||||
def __init__(self, controller, presentation):
|
||||
log.debug(u'Init Presentation OpenOffice')
|
||||
self.controller = controller
|
||||
self.document = None
|
||||
self.presentation = None
|
||||
self.control = None
|
||||
self.store_filename(presentation)
|
||||
|
||||
def load_presentation(self):
|
||||
"""
|
||||
Called when a presentation is added to the SlideController.
|
||||
It builds the environment, starts communcations with the background
|
||||
|
@ -121,20 +190,21 @@ class ImpressController(PresentationController):
|
|||
``presentation``
|
||||
The file name of the presentatios to the run.
|
||||
"""
|
||||
log.debug(u'LoadPresentation')
|
||||
self.store_filename(presentation)
|
||||
log.debug(u'Load Presentation OpenOffice')
|
||||
#print "s.dsk1 ", self.desktop
|
||||
if os.name == u'nt':
|
||||
desktop = self.get_com_desktop()
|
||||
desktop = self.controller.get_com_desktop()
|
||||
if desktop is None:
|
||||
self.start_process()
|
||||
desktop = self.get_com_desktop()
|
||||
url = u'file:///' + presentation.replace(u'\\', u'/').replace(u':', u'|').replace(u' ', u'%20')
|
||||
self.controller.start_process()
|
||||
desktop = self.controller.get_com_desktop()
|
||||
url = u'file:///' + self.filepath.replace(u'\\', u'/').replace(u':', u'|').replace(u' ', u'%20')
|
||||
else:
|
||||
desktop = self.get_uno_desktop()
|
||||
url = uno.systemPathToFileUrl(presentation)
|
||||
desktop = self.controller.get_uno_desktop()
|
||||
url = uno.systemPathToFileUrl(self.filepath)
|
||||
if desktop is None:
|
||||
return
|
||||
self.desktop = desktop
|
||||
#print "s.dsk2 ", self.desktop
|
||||
properties = []
|
||||
properties.append(self.create_property(u'Minimized', True))
|
||||
properties = tuple(properties)
|
||||
|
@ -145,17 +215,17 @@ class ImpressController(PresentationController):
|
|||
log.exception(u'Failed to load presentation')
|
||||
return
|
||||
self.presentation = self.document.getPresentation()
|
||||
self.presentation.Display = self.plugin.render_manager.current_display + 1
|
||||
self.controller = None
|
||||
self.presentation.Display = self.controller.plugin.render_manager.screens.current_display + 1
|
||||
self.control = None
|
||||
self.create_thumbnails()
|
||||
|
||||
|
||||
def create_thumbnails(self):
|
||||
"""
|
||||
Create thumbnail images for presentation
|
||||
"""
|
||||
log.debug(u'create thumbnails OpenOffice')
|
||||
if self.check_thumbnails():
|
||||
return
|
||||
|
||||
if os.name == u'nt':
|
||||
thumbdir = u'file:///' + self.thumbnailpath.replace(
|
||||
u'\\', u'/').replace(u':', u'|').replace(u' ', u'%20')
|
||||
|
@ -169,129 +239,120 @@ class ImpressController(PresentationController):
|
|||
for idx in range(pages.getCount()):
|
||||
page = pages.getByIndex(idx)
|
||||
doc.getCurrentController().setCurrentPage(page)
|
||||
doc.storeToURL(thumbdir + u'/' + self.thumbnailprefix +
|
||||
unicode(idx+1) + u'.png', props)
|
||||
path = u'%s/%s%s.png'% (thumbdir, self.controller.thumbnailprefix,
|
||||
unicode(idx + 1))
|
||||
try:
|
||||
doc.storeToURL(path , props)
|
||||
except:
|
||||
log.exception(u'%s\nUnable to store preview' % path)
|
||||
|
||||
def create_property(self, name, value):
|
||||
log.debug(u'create property OpenOffice')
|
||||
if os.name == u'nt':
|
||||
prop = self.manager.Bridge_GetStruct(u'com.sun.star.beans.PropertyValue')
|
||||
prop = self.controller.manager.Bridge_GetStruct(u'com.sun.star.beans.PropertyValue')
|
||||
else:
|
||||
prop = PropertyValue()
|
||||
prop.Name = name
|
||||
prop.Value = value
|
||||
return prop
|
||||
|
||||
def get_uno_desktop(self):
|
||||
log.debug(u'getUNODesktop')
|
||||
ctx = None
|
||||
loop = 0
|
||||
context = uno.getComponentContext()
|
||||
resolver = context.ServiceManager.createInstanceWithContext(
|
||||
u'com.sun.star.bridge.UnoUrlResolver', context)
|
||||
while ctx is None and loop < 3:
|
||||
try:
|
||||
ctx = resolver.resolve(u'uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext')
|
||||
except:
|
||||
self.start_process()
|
||||
loop += 1
|
||||
try:
|
||||
self.manager = ctx.ServiceManager
|
||||
desktop = self.manager.createInstanceWithContext(
|
||||
"com.sun.star.frame.Desktop", ctx )
|
||||
return desktop
|
||||
except:
|
||||
log.exception(u'Failed to get UNO desktop')
|
||||
return None
|
||||
|
||||
def get_com_desktop(self):
|
||||
log.debug(u'getCOMDesktop')
|
||||
try:
|
||||
desktop = self.manager.createInstance(u'com.sun.star.frame.Desktop')
|
||||
return desktop
|
||||
except:
|
||||
log.exception(u'Failed to get COM desktop')
|
||||
return None
|
||||
|
||||
def get_com_servicemanager(self):
|
||||
log.debug(u'get_com_servicemanager')
|
||||
try:
|
||||
return Dispatch(u'com.sun.star.ServiceManager')
|
||||
except:
|
||||
log.exception(u'Failed to get COM service manager')
|
||||
return None
|
||||
|
||||
def close_presentation(self):
|
||||
"""
|
||||
Close presentation and clean up objects
|
||||
Triggerent by new object being added to SlideController orOpenLP
|
||||
being shut down
|
||||
Triggered by new object being added to SlideController or OpenLP
|
||||
being shutdown
|
||||
"""
|
||||
log.debug(u'close Presentation OpenOffice')
|
||||
if self.document:
|
||||
if self.presentation:
|
||||
self.presentation.end()
|
||||
self.presentation = None
|
||||
self.document.dispose()
|
||||
try:
|
||||
self.presentation.end()
|
||||
self.presentation = None
|
||||
self.document.dispose()
|
||||
except:
|
||||
#We tried!
|
||||
pass
|
||||
self.document = None
|
||||
self.controller.remove_doc(self)
|
||||
|
||||
def is_loaded(self):
|
||||
log.debug(u'is loaded OpenOffice')
|
||||
#print "is_loaded "
|
||||
if self.presentation is None or self.document is None:
|
||||
#print "no present or document"
|
||||
return False
|
||||
try:
|
||||
if self.document.getPresentation() is None:
|
||||
#print "no getPresentation"
|
||||
return False
|
||||
except:
|
||||
return False
|
||||
return True
|
||||
|
||||
def is_active(self):
|
||||
log.debug(u'is active OpenOffice')
|
||||
#print "is_active "
|
||||
if not self.is_loaded():
|
||||
#print "False "
|
||||
return False
|
||||
if self.controller is None:
|
||||
#print "self.con ", self.control
|
||||
if self.control is None:
|
||||
return False
|
||||
return self.controller.isRunning() and self.controller.isActive()
|
||||
return True
|
||||
|
||||
def unblank_screen(self):
|
||||
return self.controller.resume()
|
||||
log.debug(u'unblank screen OpenOffice')
|
||||
return self.control.resume()
|
||||
|
||||
def blank_screen(self):
|
||||
self.controller.blankScreen(0)
|
||||
log.debug(u'blank screen OpenOffice')
|
||||
self.control.blankScreen(0)
|
||||
|
||||
def is_blank(self):
|
||||
"""
|
||||
Returns true if screen is blank
|
||||
"""
|
||||
log.debug(u'is blank OpenOffice')
|
||||
return self.control.isPaused()
|
||||
|
||||
def stop_presentation(self):
|
||||
self.controller.deactivate()
|
||||
log.debug(u'stop presentation OpenOffice')
|
||||
self.control.deactivate()
|
||||
|
||||
def start_presentation(self):
|
||||
if self.controller is None or not self.controller.isRunning():
|
||||
log.debug(u'start presentation OpenOffice')
|
||||
if self.control is None or not self.control.isRunning():
|
||||
self.presentation.start()
|
||||
# start() returns before the getCurrentComponent is ready. Try for 5 seconds
|
||||
i = 1
|
||||
while self.desktop.getCurrentComponent() is None and i < 50:
|
||||
time.sleep(0.1)
|
||||
i = i + 1
|
||||
self.controller = self.desktop.getCurrentComponent().Presentation.getController()
|
||||
self.control = self.desktop.getCurrentComponent().Presentation.getController()
|
||||
else:
|
||||
self.controller.activate()
|
||||
self.control.activate()
|
||||
self.goto_slide(1)
|
||||
|
||||
def get_slide_number(self):
|
||||
return self.controller.getCurrentSlideIndex() + 1
|
||||
return self.control.getCurrentSlideIndex() + 1
|
||||
|
||||
def get_slide_count(self):
|
||||
return self.document.getDrawPages().getCount()
|
||||
|
||||
def goto_slide(self, slideno):
|
||||
self.controller.gotoSlideIndex(slideno-1)
|
||||
self.control.gotoSlideIndex(slideno-1)
|
||||
|
||||
def next_step(self):
|
||||
"""
|
||||
Triggers the next effect of slide on the running presentation
|
||||
"""
|
||||
self.controller.gotoNextEffect()
|
||||
self.control.gotoNextEffect()
|
||||
|
||||
def previous_step(self):
|
||||
"""
|
||||
Triggers the previous slide on the running presentation
|
||||
"""
|
||||
self.controller.gotoPreviousSlide()
|
||||
self.control.gotoPreviousSlide()
|
||||
|
||||
def get_slide_preview_file(self, slide_no):
|
||||
"""
|
||||
|
@ -301,8 +362,43 @@ class ImpressController(PresentationController):
|
|||
The slide an image is required for, starting at 1
|
||||
"""
|
||||
path = os.path.join(self.thumbnailpath,
|
||||
self.thumbnailprefix + unicode(slide_no) + u'.png')
|
||||
self.controller.thumbnailprefix + unicode(slide_no) + u'.png')
|
||||
if os.path.isfile(path):
|
||||
return path
|
||||
else:
|
||||
return None
|
||||
return None
|
||||
|
||||
def get_slide_text(self, slide_no):
|
||||
"""
|
||||
Returns the text on the slide
|
||||
|
||||
``slide_no``
|
||||
The slide the text is required for, starting at 1
|
||||
"""
|
||||
doc = self.document
|
||||
pages = doc.getDrawPages()
|
||||
text = ''
|
||||
page = pages.getByIndex(slide_no - 1)
|
||||
for idx in range(page.getCount()):
|
||||
shape = page.getByIndex(idx)
|
||||
if shape.supportsService("com.sun.star.drawing.Text"):
|
||||
text += shape.getString() + '\n'
|
||||
return text
|
||||
|
||||
def get_slide_notes(self, slide_no):
|
||||
"""
|
||||
Returns the text on the slide
|
||||
|
||||
``slide_no``
|
||||
The slide the notes are required for, starting at 1
|
||||
"""
|
||||
doc = self.document
|
||||
pages = doc.getDrawPages()
|
||||
text = ''
|
||||
page = pages.getByIndex(slide_no - 1)
|
||||
notes = page.getNotesPage()
|
||||
for idx in range(notes.getCount()):
|
||||
shape = notes.getByIndex(idx)
|
||||
if shape.supportsService("com.sun.star.drawing.Text"):
|
||||
text += shape.getString() + '\n'
|
||||
return text
|
||||
|
|
|
@ -31,6 +31,8 @@ from PyQt4 import QtCore, QtGui
|
|||
from openlp.core.lib import MediaManagerItem, BaseListWithDnD
|
||||
from openlp.plugins.presentations.lib import MessageListener
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
# We have to explicitly create separate classes for each plugin
|
||||
# in order for DnD to the Service manager to work correctly.
|
||||
class PresentationListView(BaseListWithDnD):
|
||||
|
@ -43,8 +45,6 @@ class PresentationMediaItem(MediaManagerItem):
|
|||
This is the Presentation media manager item for Presentation Items.
|
||||
It can present files using Openoffice
|
||||
"""
|
||||
global log
|
||||
log = logging.getLogger(u'PresentationsMediaItem')
|
||||
log.info(u'Presentations Media Item loaded')
|
||||
|
||||
def __init__(self, parent, icon, title, controllers):
|
||||
|
@ -52,18 +52,27 @@ class PresentationMediaItem(MediaManagerItem):
|
|||
self.PluginNameShort = u'Presentation'
|
||||
self.ConfigSection = title
|
||||
self.IconPath = u'presentations/presentation'
|
||||
self.Automatic = u''
|
||||
# this next is a class, not an instance of a class - it will
|
||||
# be instanced by the base MediaManagerItem
|
||||
self.ListViewWithDnD_class = PresentationListView
|
||||
MediaManagerItem.__init__(self, parent, icon, title)
|
||||
self.message_listener = MessageListener(controllers)
|
||||
|
||||
self.message_listener = MessageListener(self)
|
||||
|
||||
def initPluginNameVisible(self):
|
||||
self.PluginNameVisible = self.trUtf8('Presentation')
|
||||
|
||||
def retranslateUi(self):
|
||||
self.OnNewPrompt = self.trUtf8('Select Presentation(s)')
|
||||
self.OnNewFileMasks = self.trUtf8('Presentations (*.ppt *.pps *.odp)')
|
||||
self.Automatic = self.trUtf8('Automatic')
|
||||
fileType = u''
|
||||
for controller in self.controllers:
|
||||
if self.controllers[controller].enabled:
|
||||
types = self.controllers[controller].supports + self.controllers[controller].alsosupports
|
||||
for type in types:
|
||||
if fileType.find(type) == -1:
|
||||
fileType += u'*%s ' % type
|
||||
self.OnNewFileMasks = self.trUtf8('Presentations (%s)' % fileType)
|
||||
|
||||
def requiredIcons(self):
|
||||
MediaManagerItem.requiredIcons(self)
|
||||
|
@ -100,6 +109,9 @@ class PresentationMediaItem(MediaManagerItem):
|
|||
#load the drop down selection
|
||||
if self.controllers[item].enabled:
|
||||
self.DisplayTypeComboBox.addItem(item)
|
||||
if self.DisplayTypeComboBox.count() > 1:
|
||||
self.DisplayTypeComboBox.insertItem(0, self.Automatic)
|
||||
self.DisplayTypeComboBox.setCurrentIndex(0)
|
||||
|
||||
def loadList(self, list):
|
||||
currlist = self.getFileList()
|
||||
|
@ -129,7 +141,9 @@ class PresentationMediaItem(MediaManagerItem):
|
|||
self.ConfigSection, self.getFileList())
|
||||
filepath = unicode((item.data(QtCore.Qt.UserRole)).toString())
|
||||
for cidx in self.controllers:
|
||||
self.controllers[cidx].presentation_deleted(filepath)
|
||||
doc = self.controllers[cidx].add_doc(filepath)
|
||||
doc.presentation_deleted()
|
||||
self.controllers[cidx].remove_doc(doc)
|
||||
|
||||
def generateSlideData(self, service_item):
|
||||
items = self.ListView.selectedIndexes()
|
||||
|
@ -137,18 +151,39 @@ class PresentationMediaItem(MediaManagerItem):
|
|||
return False
|
||||
service_item.title = unicode(self.DisplayTypeComboBox.currentText())
|
||||
service_item.shortname = unicode(self.DisplayTypeComboBox.currentText())
|
||||
controller = self.controllers[service_item.shortname]
|
||||
shortname = service_item.shortname
|
||||
|
||||
for item in items:
|
||||
bitem = self.ListView.item(item.row())
|
||||
filename = unicode((bitem.data(QtCore.Qt.UserRole)).toString())
|
||||
if shortname == self.Automatic:
|
||||
service_item.shortname = self.findControllerByType(filename)
|
||||
if not service_item.shortname:
|
||||
return False
|
||||
controller = self.controllers[service_item.shortname]
|
||||
(path, name) = os.path.split(filename)
|
||||
controller.store_filename(filename)
|
||||
if controller.get_slide_preview_file(1) is None:
|
||||
controller.load_presentation(filename)
|
||||
doc = controller.add_doc(filename)
|
||||
if doc.get_slide_preview_file(1) is None:
|
||||
doc.load_presentation()
|
||||
i = 1
|
||||
img = controller.get_slide_preview_file(i)
|
||||
img = doc.get_slide_preview_file(i)
|
||||
while img:
|
||||
service_item.add_from_command(path, name, img)
|
||||
i = i + 1
|
||||
img = controller.get_slide_preview_file(i)
|
||||
return True
|
||||
img = doc.get_slide_preview_file(i)
|
||||
controller.remove_doc(doc)
|
||||
return True
|
||||
|
||||
def findControllerByType(self, filename):
|
||||
filetype = os.path.splitext(filename)[1]
|
||||
if not filetype:
|
||||
return None
|
||||
for controller in self.controllers:
|
||||
if self.controllers[controller].enabled:
|
||||
if filetype in self.controllers[controller].supports:
|
||||
return controller
|
||||
for controller in self.controllers:
|
||||
if self.controllers[controller].enabled:
|
||||
if filetype in self.controllers[controller].alsosupports:
|
||||
return controller
|
||||
return None
|
||||
|
|
|
@ -30,136 +30,160 @@ from PyQt4 import QtCore
|
|||
|
||||
from openlp.core.lib import Receiver
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
class Controller(object):
|
||||
"""
|
||||
This is the Presentation listener who acts on events from the slide
|
||||
controller and passes the messages on the the correct presentation handlers
|
||||
"""
|
||||
global log
|
||||
log = logging.getLogger(u'Controller')
|
||||
log.info(u'Controller loaded')
|
||||
|
||||
def __init__(self, live):
|
||||
self.isLive = live
|
||||
self.doc = None
|
||||
log.info(u'%s controller loaded' % live)
|
||||
|
||||
def addHandler(self, controller, file):
|
||||
def addHandler(self, controller, file, isBlank):
|
||||
log.debug(u'Live = %s, addHandler %s' % (self.isLive, file))
|
||||
self.controller = controller
|
||||
if self.controller.is_loaded():
|
||||
self.shutdown(None)
|
||||
self.controller.load_presentation(file)
|
||||
if self.doc is not None:
|
||||
self.shutdown()
|
||||
self.doc = self.controller.add_doc(file)
|
||||
self.doc.load_presentation()
|
||||
if self.isLive:
|
||||
self.controller.start_presentation()
|
||||
self.doc.start_presentation()
|
||||
if isBlank:
|
||||
self.blank()
|
||||
Receiver.send_message(u'live_slide_hide')
|
||||
self.controller.slidenumber = 0
|
||||
self.doc.slidenumber = 0
|
||||
|
||||
def activate(self):
|
||||
log.debug(u'Live = %s, activate' % self.isLive)
|
||||
if self.controller.is_active():
|
||||
if self.doc.is_active():
|
||||
return
|
||||
if not self.controller.is_loaded():
|
||||
self.controller.load_presentation(self.controller.filepath)
|
||||
if not self.doc.is_loaded():
|
||||
self.doc.load_presentation()
|
||||
if self.isLive:
|
||||
self.controller.start_presentation()
|
||||
if self.controller.slidenumber > 1:
|
||||
self.controller.goto_slide(self.controller.slidenumber)
|
||||
self.doc.start_presentation()
|
||||
if self.doc.slidenumber > 1:
|
||||
self.doc.goto_slide(self.doc.slidenumber)
|
||||
|
||||
def slide(self, slide, live):
|
||||
log.debug(u'Live = %s, slide' % live)
|
||||
# if not isLive:
|
||||
# return
|
||||
if not live:
|
||||
return
|
||||
if self.doc.is_blank():
|
||||
self.doc.slidenumber = int(slide) + 1
|
||||
return
|
||||
self.activate()
|
||||
self.controller.goto_slide(int(slide) + 1)
|
||||
self.controller.poll_slidenumber(live)
|
||||
self.doc.goto_slide(int(slide) + 1)
|
||||
self.doc.poll_slidenumber(live)
|
||||
|
||||
def first(self, message):
|
||||
def first(self):
|
||||
"""
|
||||
Based on the handler passed at startup triggers the first slide
|
||||
"""
|
||||
log.debug(u'Live = %s, first' % self.isLive)
|
||||
print "first ", message
|
||||
if not self.isLive:
|
||||
return
|
||||
if self.doc.is_blank():
|
||||
self.doc.slidenumber = 1
|
||||
return
|
||||
self.activate()
|
||||
self.controller.start_presentation()
|
||||
self.controller.poll_slidenumber(self.isLive)
|
||||
self.doc.start_presentation()
|
||||
self.doc.poll_slidenumber(self.isLive)
|
||||
|
||||
def last(self, message):
|
||||
def last(self):
|
||||
"""
|
||||
Based on the handler passed at startup triggers the first slide
|
||||
"""
|
||||
log.debug(u'Live = %s, last' % self.isLive)
|
||||
print "last ", message
|
||||
if not self.isLive:
|
||||
return
|
||||
if self.doc.is_blank():
|
||||
self.doc.slidenumber = self.doc.get_slide_count()
|
||||
return
|
||||
self.activate()
|
||||
self.controller.goto_slide(self.controller.get_slide_count())
|
||||
self.controller.poll_slidenumber(self.isLive)
|
||||
self.doc.goto_slide(self.doc.get_slide_count())
|
||||
self.doc.poll_slidenumber(self.isLive)
|
||||
|
||||
def next(self, message):
|
||||
def next(self):
|
||||
"""
|
||||
Based on the handler passed at startup triggers the next slide event
|
||||
"""
|
||||
log.debug(u'Live = %s, next' % self.isLive)
|
||||
print "next ", message
|
||||
if not self.isLive:
|
||||
return
|
||||
if self.doc.is_blank():
|
||||
if self.doc.slidenumber < self.doc.get_slide_count():
|
||||
self.doc.slidenumber = self.doc.slidenumber + 1
|
||||
return
|
||||
self.activate()
|
||||
self.controller.next_step()
|
||||
self.controller.poll_slidenumber(self.isLive)
|
||||
self.doc.next_step()
|
||||
self.doc.poll_slidenumber(self.isLive)
|
||||
|
||||
def previous(self, message):
|
||||
def previous(self):
|
||||
"""
|
||||
Based on the handler passed at startup triggers the previous slide event
|
||||
"""
|
||||
log.debug(u'Live = %s, previous' % self.isLive)
|
||||
if not self.isLive:
|
||||
return
|
||||
print "previous ", message
|
||||
if self.doc.is_blank():
|
||||
if self.doc.slidenumber > 1:
|
||||
self.doc.slidenumber = self.doc.slidenumber - 1
|
||||
return
|
||||
self.activate()
|
||||
self.controller.previous_step()
|
||||
self.controller.poll_slidenumber(self.isLive)
|
||||
self.doc.previous_step()
|
||||
self.doc.poll_slidenumber(self.isLive)
|
||||
|
||||
def shutdown(self, message):
|
||||
def shutdown(self):
|
||||
"""
|
||||
Based on the handler passed at startup triggers slide show to shut down
|
||||
"""
|
||||
log.debug(u'Live = %s, shutdown' % self.isLive)
|
||||
self.controller.close_presentation()
|
||||
self.controller.slidenumber = 0
|
||||
if self.isLive:
|
||||
Receiver.send_message(u'live_slide_show')
|
||||
self.doc.close_presentation()
|
||||
self.doc = None
|
||||
#self.doc.slidenumber = 0
|
||||
#self.timer.stop()
|
||||
|
||||
def blank(self):
|
||||
log.debug(u'Live = %s, blank' % self.isLive)
|
||||
if not self.isLive:
|
||||
return
|
||||
if not self.controller.is_loaded():
|
||||
if not self.doc.is_loaded():
|
||||
return
|
||||
if not self.controller.is_active():
|
||||
if not self.doc.is_active():
|
||||
return
|
||||
self.controller.blank_screen()
|
||||
self.doc.blank_screen()
|
||||
|
||||
def unblank(self):
|
||||
if not self.is_live:
|
||||
log.debug(u'Live = %s, unblank' % self.isLive)
|
||||
if not self.isLive:
|
||||
return
|
||||
self.activate()
|
||||
self.controller.unblank_screen()
|
||||
if self.doc.slidenumber and self.doc.slidenumber != self.doc.get_slide_number():
|
||||
self.doc.goto_slide(self.doc.slidenumber)
|
||||
self.doc.unblank_screen()
|
||||
|
||||
def poll(self):
|
||||
self.doc.poll_slidenumber(self.isLive)
|
||||
|
||||
class MessageListener(object):
|
||||
"""
|
||||
This is the Presentation listener who acts on events from the slide
|
||||
controller and passes the messages on the the correct presentation handlers
|
||||
"""
|
||||
global log
|
||||
log = logging.getLogger(u'MessageListener')
|
||||
log.info(u'Message Listener loaded')
|
||||
|
||||
def __init__(self, controllers):
|
||||
self.controllers = controllers
|
||||
def __init__(self, mediaitem):
|
||||
self.controllers = mediaitem.controllers
|
||||
self.mediaitem = mediaitem
|
||||
self.previewHandler = Controller(False)
|
||||
self.liveHandler = Controller(True)
|
||||
self.isLive = None
|
||||
# messages are sent from core.ui.slidecontroller
|
||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||
QtCore.SIGNAL(u'presentations_start'), self.startup)
|
||||
|
@ -189,11 +213,17 @@ class MessageListener(object):
|
|||
Save the handler as any new presentations start here
|
||||
"""
|
||||
log.debug(u'Startup called with message %s' % message)
|
||||
self.handler, file, isLive = self.decodeMessage(message)
|
||||
self.handler, file, isLive, isBlank = self.decodeMessage(message)
|
||||
if self.handler == self.mediaitem.Automatic:
|
||||
self.handler = self.mediaitem.findControllerByType(file)
|
||||
if not self.handler:
|
||||
return
|
||||
|
||||
if isLive:
|
||||
self.liveHandler.addHandler(self.controllers[self.handler], file)
|
||||
controller = self.liveHandler
|
||||
else:
|
||||
self.previewHandler.addHandler(self.controllers[self.handler], file)
|
||||
controller = self.previewHandler
|
||||
controller.addHandler(self.controllers[self.handler], file, isBlank)
|
||||
|
||||
def slide(self, message):
|
||||
slide, live = self.splitMessage(message)
|
||||
|
@ -202,48 +232,42 @@ class MessageListener(object):
|
|||
else:
|
||||
self.previewHandler.slide(slide, live)
|
||||
|
||||
def first(self, message):
|
||||
if self.isLive:
|
||||
self.liveHandler.first(message)
|
||||
def first(self, isLive):
|
||||
if isLive:
|
||||
self.liveHandler.first()
|
||||
else:
|
||||
self.previewHandler.first(message)
|
||||
self.previewHandler.first()
|
||||
|
||||
def last(self, message):
|
||||
if self.isLive:
|
||||
self.liveHandler.last(message)
|
||||
def last(self, isLive):
|
||||
if isLive:
|
||||
self.liveHandler.last()
|
||||
else:
|
||||
self.previewHandler.last(message)
|
||||
self.previewHandler.last()
|
||||
|
||||
def next(self, message):
|
||||
if self.isLive:
|
||||
self.liveHandler.next(message)
|
||||
def next(self, isLive):
|
||||
if isLive:
|
||||
self.liveHandler.next()
|
||||
else:
|
||||
self.previewHandler.next(message)
|
||||
self.previewHandler.next()
|
||||
|
||||
def previous(self, message):
|
||||
if self.isLive:
|
||||
self.liveHandler.previous(message)
|
||||
def previous(self, isLive):
|
||||
if isLive:
|
||||
self.liveHandler.previous()
|
||||
else:
|
||||
self.previewHandler.previous(message)
|
||||
self.previewHandler.previous()
|
||||
|
||||
def shutdown(self, message):
|
||||
if self.isLive:
|
||||
self.liveHandler.shutdown(message)
|
||||
def shutdown(self, isLive):
|
||||
if isLive:
|
||||
self.liveHandler.shutdown()
|
||||
Receiver.send_message(u'live_slide_show')
|
||||
else:
|
||||
self.previewHandler.shutdown(message)
|
||||
self.previewHandler.shutdown()
|
||||
|
||||
def blank(self):
|
||||
if self.isLive:
|
||||
self.liveHandler.blank()
|
||||
else:
|
||||
self.previewHandler.blank()
|
||||
self.liveHandler.blank()
|
||||
|
||||
def unblank(self):
|
||||
if self.isLive:
|
||||
self.liveHandler.unblank()
|
||||
else:
|
||||
self.previewHandler.unblank()
|
||||
self.liveHandler.unblank()
|
||||
|
||||
def splitMessage(self, message):
|
||||
"""
|
||||
|
@ -265,7 +289,7 @@ class MessageListener(object):
|
|||
Message containing Presentaion handler name and file to be presented.
|
||||
"""
|
||||
file = os.path.join(message[1], message[2])
|
||||
return message[0], file, message[4]
|
||||
return message[0], file, message[4], message[5]
|
||||
|
||||
def timeout(self):
|
||||
self.controller.poll_slidenumber(self.is_live)
|
||||
self.liveHandler.poll()
|
||||
|
|
|
@ -31,7 +31,9 @@ if os.name == u'nt':
|
|||
import _winreg
|
||||
import win32ui
|
||||
|
||||
from presentationcontroller import PresentationController
|
||||
from presentationcontroller import PresentationController, PresentationDocument
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
# PPT API documentation:
|
||||
# http://msdn.microsoft.com/en-us/library/aa269321(office.10).aspx
|
||||
|
@ -42,9 +44,7 @@ class PowerpointController(PresentationController):
|
|||
It creates the runtime Environment , Loads the and Closes the Presentation
|
||||
As well as triggering the correct activities based on the users input
|
||||
"""
|
||||
global log
|
||||
log = logging.getLogger(u'PowerpointController')
|
||||
log.info(u'loaded')
|
||||
log.info(u'PowerpointController loaded')
|
||||
|
||||
def __init__(self, plugin):
|
||||
"""
|
||||
|
@ -52,8 +52,8 @@ class PowerpointController(PresentationController):
|
|||
"""
|
||||
log.debug(u'Initialising')
|
||||
PresentationController.__init__(self, plugin, u'Powerpoint')
|
||||
self.supports = [u'.ppt', u'.pps', u'.pptx', u'.ppsx']
|
||||
self.process = None
|
||||
self.presentation = None
|
||||
|
||||
def check_available(self):
|
||||
"""
|
||||
|
@ -77,121 +77,145 @@ class PowerpointController(PresentationController):
|
|||
self.process.Visible = True
|
||||
self.process.WindowState = 2
|
||||
|
||||
def is_loaded(self):
|
||||
"""
|
||||
Returns true if a presentation is loaded
|
||||
"""
|
||||
try:
|
||||
if not self.process.Visible:
|
||||
return False
|
||||
if self.process.Windows.Count == 0:
|
||||
return False
|
||||
if self.process.Presentations.Count == 0:
|
||||
return False
|
||||
except:
|
||||
return False
|
||||
return True
|
||||
|
||||
def kill(self):
|
||||
"""
|
||||
Called at system exit to clean up any running presentations
|
||||
"""
|
||||
for doc in self.docs:
|
||||
doc.close_presentation()
|
||||
if self.process is None:
|
||||
return
|
||||
if self.process.Presentations.Count > 0:
|
||||
return
|
||||
try:
|
||||
self.process.Quit()
|
||||
except:
|
||||
pass
|
||||
self.process = None
|
||||
|
||||
def load_presentation(self, presentation):
|
||||
"""
|
||||
Called when a presentation is added to the SlideController.
|
||||
It builds the environment, starts communcations with the background
|
||||
OpenOffice task started earlier. If OpenOffice is not present is is
|
||||
started. Once the environment is available the presentation is loaded
|
||||
and started.
|
||||
def add_doc(self, name):
|
||||
log.debug(u'Add Doc PowerPoint')
|
||||
doc = PowerpointDocument(self, name)
|
||||
self.docs.append(doc)
|
||||
return doc
|
||||
|
||||
``presentation``
|
||||
The file name of the presentations to run.
|
||||
"""
|
||||
log.debug(u'LoadPresentation')
|
||||
self.store_filename(presentation)
|
||||
try:
|
||||
if not self.process.Visible:
|
||||
self.start_process()
|
||||
except:
|
||||
self.start_process()
|
||||
try:
|
||||
self.process.Presentations.Open(presentation, False, False, True)
|
||||
except:
|
||||
return
|
||||
self.presentation = self.process.Presentations(self.process.Presentations.Count)
|
||||
self.create_thumbnails()
|
||||
class PowerpointDocument(PresentationDocument):
|
||||
|
||||
def create_thumbnails(self):
|
||||
"""
|
||||
Create the thumbnail images for the current presentation.
|
||||
Note an alternative and quicker method would be do
|
||||
self.presentation.Slides[n].Copy()
|
||||
thumbnail = QApplication.clipboard.image()
|
||||
But for now we want a physical file since it makes
|
||||
life easier elsewhere
|
||||
"""
|
||||
if self.check_thumbnails():
|
||||
return
|
||||
self.presentation.Export(os.path.join(self.thumbnailpath, '')
|
||||
, 'png', 600, 480)
|
||||
def __init__(self, controller, presentation):
|
||||
log.debug(u'Init Presentation Powerpoint')
|
||||
self.presentation = None
|
||||
self.controller = controller
|
||||
self.store_filename(presentation)
|
||||
|
||||
def close_presentation(self):
|
||||
"""
|
||||
Close presentation and clean up objects
|
||||
Triggerent by new object being added to SlideController orOpenLP
|
||||
being shut down
|
||||
"""
|
||||
if self.presentation == None:
|
||||
return
|
||||
try:
|
||||
self.presentation.Close()
|
||||
except:
|
||||
pass
|
||||
self.presentation = None
|
||||
def load_presentation(self):
|
||||
"""
|
||||
Called when a presentation is added to the SlideController.
|
||||
It builds the environment, starts communcations with the background
|
||||
OpenOffice task started earlier. If OpenOffice is not present is is
|
||||
started. Once the environment is available the presentation is loaded
|
||||
and started.
|
||||
|
||||
def is_active(self):
|
||||
"""
|
||||
Returns true if a presentation is currently active
|
||||
"""
|
||||
if not self.is_loaded():
|
||||
``presentation``
|
||||
The file name of the presentations to run.
|
||||
"""
|
||||
log.debug(u'LoadPresentation')
|
||||
if not self.controller.process.Visible:
|
||||
self.controller.start_process()
|
||||
#try:
|
||||
self.controller.process.Presentations.Open(self.filepath, False, False, True)
|
||||
#except:
|
||||
# return
|
||||
self.presentation = self.controller.process.Presentations(
|
||||
self.controller.process.Presentations.Count)
|
||||
self.create_thumbnails()
|
||||
|
||||
def create_thumbnails(self):
|
||||
"""
|
||||
Create the thumbnail images for the current presentation.
|
||||
Note an alternative and quicker method would be do
|
||||
self.presentation.Slides[n].Copy()
|
||||
thumbnail = QApplication.clipboard.image()
|
||||
But for now we want a physical file since it makes
|
||||
life easier elsewhere
|
||||
"""
|
||||
if self.check_thumbnails():
|
||||
return
|
||||
self.presentation.Export(os.path.join(self.thumbnailpath, '')
|
||||
, 'png', 640, 480)
|
||||
|
||||
def close_presentation(self):
|
||||
"""
|
||||
Close presentation and clean up objects
|
||||
Triggerent by new object being added to SlideController orOpenLP
|
||||
being shut down
|
||||
"""
|
||||
if self.presentation is None:
|
||||
return
|
||||
try:
|
||||
self.presentation.Close()
|
||||
except:
|
||||
pass
|
||||
self.presentation = None
|
||||
self.controller.remove_doc(self)
|
||||
|
||||
def is_loaded(self):
|
||||
"""
|
||||
Returns true if a presentation is loaded
|
||||
"""
|
||||
try:
|
||||
if not self.controller.process.Visible:
|
||||
return False
|
||||
try:
|
||||
if self.presentation.SlideShowWindow == None:
|
||||
return False
|
||||
if self.presentation.SlideShowWindow.View == None:
|
||||
return False
|
||||
except:
|
||||
if self.controller.process.Windows.Count == 0:
|
||||
return False
|
||||
return True
|
||||
if self.controller.process.Presentations.Count == 0:
|
||||
return False
|
||||
except:
|
||||
return False
|
||||
return True
|
||||
|
||||
def unblank_screen(self):
|
||||
"""
|
||||
Unblanks (restores) the presentationn
|
||||
"""
|
||||
self.presentation.SlideShowSettings.Run()
|
||||
self.presentation.SlideShowWindow.View.State = 1
|
||||
self.presentation.SlideShowWindow.Activate()
|
||||
|
||||
def blank_screen(self):
|
||||
"""
|
||||
Blanks the screen
|
||||
"""
|
||||
self.presentation.SlideShowWindow.View.State = 3
|
||||
def is_active(self):
|
||||
"""
|
||||
Returns true if a presentation is currently active
|
||||
"""
|
||||
if not self.is_loaded():
|
||||
return False
|
||||
try:
|
||||
if self.presentation.SlideShowWindow is None:
|
||||
return False
|
||||
if self.presentation.SlideShowWindow.View is None:
|
||||
return False
|
||||
except:
|
||||
return False
|
||||
return True
|
||||
|
||||
def stop_presentation(self):
|
||||
"""
|
||||
Stops the current presentation and hides the output
|
||||
"""
|
||||
self.presentation.SlideShowWindow.View.Exit()
|
||||
def unblank_screen(self):
|
||||
"""
|
||||
Unblanks (restores) the presentationn
|
||||
"""
|
||||
self.presentation.SlideShowSettings.Run()
|
||||
self.presentation.SlideShowWindow.View.State = 1
|
||||
self.presentation.SlideShowWindow.Activate()
|
||||
|
||||
def blank_screen(self):
|
||||
"""
|
||||
Blanks the screen
|
||||
"""
|
||||
self.presentation.SlideShowWindow.View.State = 3
|
||||
|
||||
def is_blank(self):
|
||||
"""
|
||||
Returns true if screen is blank
|
||||
"""
|
||||
return self.presentation.SlideShowWindow.View.State == 3
|
||||
|
||||
def stop_presentation(self):
|
||||
"""
|
||||
Stops the current presentation and hides the output
|
||||
"""
|
||||
self.presentation.SlideShowWindow.View.Exit()
|
||||
|
||||
if os.name == u'nt':
|
||||
def start_presentation(self):
|
||||
"""
|
||||
Starts a presentation from the beginning
|
||||
|
@ -206,53 +230,83 @@ class PowerpointController(PresentationController):
|
|||
dpi = 96
|
||||
self.presentation.SlideShowSettings.Run()
|
||||
self.presentation.SlideShowWindow.View.GotoSlide(1)
|
||||
rendermanager = self.plugin.render_manager
|
||||
rect = rendermanager.screen_list[rendermanager.current_display][u'size']
|
||||
rendermanager = self.controller.plugin.render_manager
|
||||
rect = rendermanager.screens.current[u'size']
|
||||
self.presentation.SlideShowWindow.Top = rect.y() * 72 / dpi
|
||||
self.presentation.SlideShowWindow.Height = rect.height() * 72 / dpi
|
||||
self.presentation.SlideShowWindow.Left = rect.x() * 72 / dpi
|
||||
self.presentation.SlideShowWindow.Width = rect.width() * 72 / dpi
|
||||
|
||||
def get_slide_number(self):
|
||||
"""
|
||||
Returns the current slide number
|
||||
"""
|
||||
return self.presentation.SlideShowWindow.View.CurrentShowPosition
|
||||
def get_slide_number(self):
|
||||
"""
|
||||
Returns the current slide number
|
||||
"""
|
||||
return self.presentation.SlideShowWindow.View.CurrentShowPosition
|
||||
|
||||
def get_slide_count(self):
|
||||
"""
|
||||
Returns total number of slides
|
||||
"""
|
||||
return self.presentation.Slides.Count
|
||||
def get_slide_count(self):
|
||||
"""
|
||||
Returns total number of slides
|
||||
"""
|
||||
return self.presentation.Slides.Count
|
||||
|
||||
def goto_slide(self, slideno):
|
||||
"""
|
||||
Moves to a specific slide in the presentation
|
||||
"""
|
||||
self.presentation.SlideShowWindow.View.GotoSlide(slideno)
|
||||
def goto_slide(self, slideno):
|
||||
"""
|
||||
Moves to a specific slide in the presentation
|
||||
"""
|
||||
self.presentation.SlideShowWindow.View.GotoSlide(slideno)
|
||||
|
||||
def next_step(self):
|
||||
"""
|
||||
Triggers the next effect of slide on the running presentation
|
||||
"""
|
||||
self.presentation.SlideShowWindow.View.Next()
|
||||
def next_step(self):
|
||||
"""
|
||||
Triggers the next effect of slide on the running presentation
|
||||
"""
|
||||
self.presentation.SlideShowWindow.View.Next()
|
||||
|
||||
def previous_step(self):
|
||||
"""
|
||||
Triggers the previous slide on the running presentation
|
||||
"""
|
||||
self.presentation.SlideShowWindow.View.Previous()
|
||||
def previous_step(self):
|
||||
"""
|
||||
Triggers the previous slide on the running presentation
|
||||
"""
|
||||
self.presentation.SlideShowWindow.View.Previous()
|
||||
|
||||
def get_slide_preview_file(self, slide_no):
|
||||
"""
|
||||
Returns an image path containing a preview for the requested slide
|
||||
def get_slide_preview_file(self, slide_no):
|
||||
"""
|
||||
Returns an image path containing a preview for the requested slide
|
||||
|
||||
``slide_no``
|
||||
The slide an image is required for, starting at 1
|
||||
"""
|
||||
path = os.path.join(self.thumbnailpath,
|
||||
self.thumbnailprefix + unicode(slide_no) + u'.png')
|
||||
if os.path.isfile(path):
|
||||
return path
|
||||
else:
|
||||
return None
|
||||
``slide_no``
|
||||
The slide an image is required for, starting at 1
|
||||
"""
|
||||
path = os.path.join(self.thumbnailpath,
|
||||
self.controller.thumbnailprefix + unicode(slide_no) + u'.png')
|
||||
if os.path.isfile(path):
|
||||
return path
|
||||
else:
|
||||
return None
|
||||
|
||||
def get_slide_text(self, slide_no):
|
||||
"""
|
||||
Returns the text on the slide
|
||||
|
||||
``slide_no``
|
||||
The slide the text is required for, starting at 1
|
||||
"""
|
||||
text = ''
|
||||
shapes = self.presentation.Slides(slide_no).Shapes
|
||||
for idx in range(shapes.Count):
|
||||
shape = shapes(idx + 1)
|
||||
if shape.HasTextFrame:
|
||||
text += shape.TextFrame.TextRange.Text + '\n'
|
||||
return text
|
||||
|
||||
def get_slide_notes(self, slide_no):
|
||||
"""
|
||||
Returns the text on the slide
|
||||
|
||||
``slide_no``
|
||||
The slide the notes are required for, starting at 1
|
||||
"""
|
||||
text = ''
|
||||
shapes = self.presentation.Slides(slide_no).NotesPage.Shapes
|
||||
for idx in range(shapes.Count):
|
||||
shape = shapes(idx + 1)
|
||||
if shape.HasTextFrame:
|
||||
text += shape.TextFrame.TextRange.Text + '\n'
|
||||
return text
|
||||
|
|
|
@ -30,7 +30,9 @@ if os.name == u'nt':
|
|||
from ctypes import *
|
||||
from ctypes.wintypes import RECT
|
||||
|
||||
from presentationcontroller import PresentationController
|
||||
from presentationcontroller import PresentationController, PresentationDocument
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
class PptviewController(PresentationController):
|
||||
"""
|
||||
|
@ -38,9 +40,7 @@ class PptviewController(PresentationController):
|
|||
It creates the runtime Environment , Loads the and Closes the Presentation
|
||||
As well as triggering the correct activities based on the users input
|
||||
"""
|
||||
global log
|
||||
log = logging.getLogger(u'PptviewController')
|
||||
log.info(u'loaded')
|
||||
log.info(u'PPTViewController loaded')
|
||||
|
||||
def __init__(self, plugin):
|
||||
"""
|
||||
|
@ -49,7 +49,7 @@ class PptviewController(PresentationController):
|
|||
log.debug(u'Initialising')
|
||||
self.process = None
|
||||
PresentationController.__init__(self, plugin, u'Powerpoint Viewer')
|
||||
self.pptid = None
|
||||
self.supports = [u'.ppt', u'.pps', u'.pptx', u'.ppsx']
|
||||
|
||||
def check_available(self):
|
||||
"""
|
||||
|
@ -89,123 +89,147 @@ class PptviewController(PresentationController):
|
|||
Called at system exit to clean up any running presentations
|
||||
"""
|
||||
log.debug(u'Kill')
|
||||
self.close_presentation()
|
||||
for doc in self.docs:
|
||||
doc.close_presentation()
|
||||
|
||||
def load_presentation(self, presentation):
|
||||
"""
|
||||
Called when a presentation is added to the SlideController.
|
||||
It builds the environment, starts communcations with the background
|
||||
OpenOffice task started earlier. If OpenOffice is not present is is
|
||||
started. Once the environment is available the presentation is loaded
|
||||
and started.
|
||||
def add_doc(self, name):
|
||||
log.debug(u'Add Doc PPTView')
|
||||
doc = PptviewDocument(self, name)
|
||||
self.docs.append(doc)
|
||||
return doc
|
||||
|
||||
``presentation``
|
||||
The file name of the presentations to run.
|
||||
"""
|
||||
log.debug(u'LoadPresentation')
|
||||
self.store_filename(presentation)
|
||||
if self.pptid >= 0:
|
||||
self.close_presentation()
|
||||
rendermanager = self.plugin.render_manager
|
||||
rect = rendermanager.screen_list[rendermanager.current_display][u'size']
|
||||
rect = RECT(rect.x(), rect.y(), rect.right(), rect.bottom())
|
||||
filepath = str(presentation.replace(u'/', u'\\'));
|
||||
try:
|
||||
self.pptid = self.process.OpenPPT(filepath, None, rect,
|
||||
str(os.path.join(self.thumbnailpath, self.thumbnailprefix)))
|
||||
self.stop_presentation()
|
||||
except:
|
||||
log.exception(u'Failed to load presentation')
|
||||
class PptviewDocument(PresentationDocument):
|
||||
|
||||
def close_presentation(self):
|
||||
"""
|
||||
Close presentation and clean up objects
|
||||
Triggerent by new object being added to SlideController orOpenLP
|
||||
being shut down
|
||||
"""
|
||||
self.process.ClosePPT(self.pptid)
|
||||
self.pptid = -1
|
||||
def __init__(self, controller, presentation):
|
||||
log.debug(u'Init Presentation PowerPoint')
|
||||
self.presentation = None
|
||||
self.pptid = None
|
||||
self.blanked = False
|
||||
self.controller = controller
|
||||
self.store_filename(presentation)
|
||||
|
||||
def is_loaded(self):
|
||||
"""
|
||||
Returns true if a presentation is loaded
|
||||
"""
|
||||
if self.pptid < 0:
|
||||
return False
|
||||
if self.get_slide_count() < 0:
|
||||
return False
|
||||
return True
|
||||
def load_presentation(self):
|
||||
"""
|
||||
Called when a presentation is added to the SlideController.
|
||||
It builds the environment, starts communcations with the background
|
||||
PptView task started earlier.
|
||||
|
||||
def is_active(self):
|
||||
"""
|
||||
Returns true if a presentation is currently active
|
||||
"""
|
||||
return self.is_loaded()
|
||||
``presentation``
|
||||
The file name of the presentations to run.
|
||||
"""
|
||||
log.debug(u'LoadPresentation')
|
||||
#if self.pptid >= 0:
|
||||
# self.close_presentation()
|
||||
rendermanager = self.controller.plugin.render_manager
|
||||
rect = rendermanager.screens.current[u'size']
|
||||
rect = RECT(rect.x(), rect.y(), rect.right(), rect.bottom())
|
||||
filepath = str(self.filepath.replace(u'/', u'\\'))
|
||||
try:
|
||||
self.pptid = self.controller.process.OpenPPT(filepath, None, rect,
|
||||
str(os.path.join(self.thumbnailpath, self.controller.thumbnailprefix)))
|
||||
self.stop_presentation()
|
||||
except:
|
||||
log.exception(u'Failed to load presentation')
|
||||
|
||||
def blank_screen(self):
|
||||
"""
|
||||
Blanks the screen
|
||||
"""
|
||||
self.process.Blank(self.pptid)
|
||||
def close_presentation(self):
|
||||
"""
|
||||
Close presentation and clean up objects
|
||||
Triggerent by new object being added to SlideController orOpenLP
|
||||
being shut down
|
||||
"""
|
||||
self.controller.process.ClosePPT(self.pptid)
|
||||
self.pptid = -1
|
||||
self.controller.remove_doc(self)
|
||||
|
||||
def unblank_screen(self):
|
||||
"""
|
||||
Unblanks (restores) the presentationn
|
||||
"""
|
||||
self.process.Unblank(self.pptid)
|
||||
def is_loaded(self):
|
||||
"""
|
||||
Returns true if a presentation is loaded
|
||||
"""
|
||||
if self.pptid < 0:
|
||||
return False
|
||||
if self.get_slide_count() < 0:
|
||||
return False
|
||||
return True
|
||||
|
||||
def stop_presentation(self):
|
||||
"""
|
||||
Stops the current presentation and hides the output
|
||||
"""
|
||||
self.process.Stop(self.pptid)
|
||||
def is_active(self):
|
||||
"""
|
||||
Returns true if a presentation is currently active
|
||||
"""
|
||||
return self.is_loaded()
|
||||
|
||||
def start_presentation(self):
|
||||
"""
|
||||
Starts a presentation from the beginning
|
||||
"""
|
||||
self.process.RestartShow(self.pptid)
|
||||
def blank_screen(self):
|
||||
"""
|
||||
Blanks the screen
|
||||
"""
|
||||
self.controller.process.Blank(self.pptid)
|
||||
self.blanked = True
|
||||
|
||||
def get_slide_number(self):
|
||||
"""
|
||||
Returns the current slide number
|
||||
"""
|
||||
return self.process.GetCurrentSlide(self.pptid)
|
||||
def unblank_screen(self):
|
||||
"""
|
||||
Unblanks (restores) the presentationn
|
||||
"""
|
||||
self.controller.process.Unblank(self.pptid)
|
||||
self.blanked = False
|
||||
|
||||
def get_slide_count(self):
|
||||
"""
|
||||
Returns total number of slides
|
||||
"""
|
||||
return self.process.GetSlideCount(self.pptid)
|
||||
def is_blank(self):
|
||||
"""
|
||||
Returns true if screen is blank
|
||||
"""
|
||||
log.debug(u'is blank OpenOffice')
|
||||
return self.blanked
|
||||
|
||||
def goto_slide(self, slideno):
|
||||
"""
|
||||
Moves to a specific slide in the presentation
|
||||
"""
|
||||
self.process.GotoSlide(self.pptid, slideno)
|
||||
def stop_presentation(self):
|
||||
"""
|
||||
Stops the current presentation and hides the output
|
||||
"""
|
||||
self.controller.process.Stop(self.pptid)
|
||||
|
||||
def next_step(self):
|
||||
"""
|
||||
Triggers the next effect of slide on the running presentation
|
||||
"""
|
||||
self.process.NextStep(self.pptid)
|
||||
def start_presentation(self):
|
||||
"""
|
||||
Starts a presentation from the beginning
|
||||
"""
|
||||
self.controller.process.RestartShow(self.pptid)
|
||||
|
||||
def previous_step(self):
|
||||
"""
|
||||
Triggers the previous slide on the running presentation
|
||||
"""
|
||||
self.process.PrevStep(self.pptid)
|
||||
def get_slide_number(self):
|
||||
"""
|
||||
Returns the current slide number
|
||||
"""
|
||||
return self.controller.process.GetCurrentSlide(self.pptid)
|
||||
|
||||
def get_slide_preview_file(self, slide_no):
|
||||
"""
|
||||
Returns an image path containing a preview for the requested slide
|
||||
def get_slide_count(self):
|
||||
"""
|
||||
Returns total number of slides
|
||||
"""
|
||||
return self.controller.process.GetSlideCount(self.pptid)
|
||||
|
||||
``slide_no``
|
||||
The slide an image is required for, starting at 1
|
||||
"""
|
||||
path = os.path.join(self.thumbnailpath,
|
||||
self.thumbnailprefix + unicode(slide_no) + u'.bmp')
|
||||
if os.path.isfile(path):
|
||||
return path
|
||||
else:
|
||||
return None
|
||||
def goto_slide(self, slideno):
|
||||
"""
|
||||
Moves to a specific slide in the presentation
|
||||
"""
|
||||
self.controller.process.GotoSlide(self.pptid, slideno)
|
||||
|
||||
def next_step(self):
|
||||
"""
|
||||
Triggers the next effect of slide on the running presentation
|
||||
"""
|
||||
self.controller.process.NextStep(self.pptid)
|
||||
|
||||
def previous_step(self):
|
||||
"""
|
||||
Triggers the previous slide on the running presentation
|
||||
"""
|
||||
self.controller.process.PrevStep(self.pptid)
|
||||
|
||||
def get_slide_preview_file(self, slide_no):
|
||||
"""
|
||||
Returns an image path containing a preview for the requested slide
|
||||
|
||||
``slide_no``
|
||||
The slide an image is required for, starting at 1
|
||||
"""
|
||||
path = os.path.join(self.thumbnailpath,
|
||||
self.controller.thumbnailprefix + unicode(slide_no) + u'.bmp')
|
||||
if os.path.isfile(path):
|
||||
return path
|
||||
else:
|
||||
return None
|
||||
|
|
|
@ -31,16 +31,16 @@ from PyQt4 import QtCore
|
|||
|
||||
from openlp.core.lib import Receiver
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
class PresentationController(object):
|
||||
"""
|
||||
Base class for presentation controllers to inherit from
|
||||
Class to control interactions with presentations.
|
||||
It creates the runtime environment, loads and closes the presentation as
|
||||
well as triggering the correct activities based on the users input
|
||||
|
||||
It creates the runtime environment
|
||||
To create a new controller, take a copy of this file and name it
|
||||
so it ends in controller.py, i.e. foobarcontroller.py
|
||||
Make sure it inhetits PresentationController
|
||||
Make sure it inherits PresentationController
|
||||
Then fill in the blanks. If possible try and make sure it loads
|
||||
on all platforms, using for example os.name checks, although
|
||||
__init__, check_available and presentation_deleted should always work.
|
||||
|
@ -73,6 +73,87 @@ class PresentationController(object):
|
|||
``presentation_deleted()``
|
||||
Deletes presentation specific files, e.g. thumbnails
|
||||
|
||||
"""
|
||||
log.info(u'PresentationController loaded')
|
||||
|
||||
def __init__(self, plugin=None, name=u'PresentationController'):
|
||||
"""
|
||||
This is the constructor for the presentationcontroller object.
|
||||
This provides an easy way for descendent plugins to populate common data.
|
||||
This method *must* be overridden, like so::
|
||||
|
||||
class MyPresentationController(PresentationController):
|
||||
def __init__(self, plugin):
|
||||
PresentationController.__init(self, plugin, u'My Presenter App')
|
||||
|
||||
``plugin``
|
||||
Defaults to *None*. The presentationplugin object
|
||||
|
||||
``name``
|
||||
Name of the application, to appear in the application
|
||||
"""
|
||||
self.supports = []
|
||||
self.alsosupports = []
|
||||
self.docs = []
|
||||
self.plugin = plugin
|
||||
self.name = name
|
||||
self.available = self.check_available()
|
||||
if self.available:
|
||||
self.enabled = int(plugin.config.get_config(
|
||||
name, QtCore.Qt.Unchecked)) == QtCore.Qt.Checked
|
||||
else:
|
||||
self.enabled = False
|
||||
self.thumbnailroot = os.path.join(plugin.config.get_data_path(),
|
||||
name, u'thumbnails')
|
||||
self.thumbnailprefix = u'slide'
|
||||
if not os.path.isdir(self.thumbnailroot):
|
||||
os.makedirs(self.thumbnailroot)
|
||||
|
||||
def check_available(self):
|
||||
"""
|
||||
Presentation app is able to run on this machine
|
||||
"""
|
||||
return False
|
||||
|
||||
|
||||
def start_process(self):
|
||||
"""
|
||||
Loads a running version of the presentation application in the background.
|
||||
"""
|
||||
pass
|
||||
|
||||
def kill(self):
|
||||
"""
|
||||
Called at system exit to clean up any running presentations and
|
||||
close the application
|
||||
"""
|
||||
log.debug(u'Kill')
|
||||
self.close_presentation()
|
||||
|
||||
def add_doc(self, name):
|
||||
"""
|
||||
Called when a new presentation document is opened
|
||||
"""
|
||||
doc = PresentationDocument(self, name)
|
||||
self.docs.append(doc)
|
||||
return doc
|
||||
|
||||
def remove_doc(self, doc):
|
||||
"""
|
||||
Called to remove an open document from the collection
|
||||
"""
|
||||
log.debug(u'remove_doc Presentation')
|
||||
self.docs.remove(doc)
|
||||
|
||||
|
||||
class PresentationDocument(object):
|
||||
"""
|
||||
Base class for presentation documents to inherit from.
|
||||
Loads and closes the presentation as well as triggering the correct
|
||||
activities based on the users input
|
||||
|
||||
**Hook Functions**
|
||||
|
||||
``load_presentation(presentation)``
|
||||
Load a presentation file
|
||||
|
||||
|
@ -91,6 +172,9 @@ class PresentationController(object):
|
|||
``unblank_screen()``
|
||||
Unblanks the screen, restoring the output
|
||||
|
||||
``is_blank``
|
||||
Returns true if screen is blank
|
||||
|
||||
``stop_presentation()``
|
||||
Stops the presentation, removing it from the output display
|
||||
|
||||
|
@ -116,70 +200,12 @@ class PresentationController(object):
|
|||
Returns a path to an image containing a preview for the requested slide
|
||||
|
||||
"""
|
||||
global log
|
||||
log = logging.getLogger(u'PresentationController')
|
||||
log.info(u'loaded')
|
||||
|
||||
def __init__(self, plugin=None, name=u'PresentationController'):
|
||||
"""
|
||||
This is the constructor for the presentationcontroller object.
|
||||
This provides an easy way for descendent plugins to populate common data.
|
||||
This method *must* be overridden, like so::
|
||||
|
||||
class MyPresentationController(PresentationController):
|
||||
def __init__(self, plugin):
|
||||
PresentationController.__init(self, plugin, u'My Presenter App')
|
||||
|
||||
``plugin``
|
||||
Defaults to *None*. The presentationplugin object
|
||||
|
||||
``name``
|
||||
Name of the application, to appear in the application
|
||||
"""
|
||||
self.plugin = plugin
|
||||
self.name = name
|
||||
self.available = self.check_available()
|
||||
def __init__(self, controller, name):
|
||||
self.slidenumber = 0
|
||||
if self.available:
|
||||
self.enabled = int(plugin.config.get_config(
|
||||
name, QtCore.Qt.Unchecked)) == QtCore.Qt.Checked
|
||||
else:
|
||||
self.enabled = False
|
||||
self.thumbnailroot = os.path.join(plugin.config.get_data_path(),
|
||||
name, u'thumbnails')
|
||||
self.thumbnailprefix = u'slide'
|
||||
if not os.path.isdir(self.thumbnailroot):
|
||||
os.makedirs(self.thumbnailroot)
|
||||
self.controller = controller
|
||||
self.store_filename(name)
|
||||
|
||||
def check_available(self):
|
||||
"""
|
||||
Presentation app is able to run on this machine
|
||||
"""
|
||||
return False
|
||||
|
||||
def presentation_deleted(self, presentation):
|
||||
"""
|
||||
Cleans up/deletes any controller specific files created for
|
||||
a file, e.g. thumbnails
|
||||
"""
|
||||
self.store_filename(presentation)
|
||||
shutil.rmtree(self.thumbnailpath)
|
||||
|
||||
def start_process(self):
|
||||
"""
|
||||
Loads a running version of the presentation application in the background.
|
||||
"""
|
||||
pass
|
||||
|
||||
def kill(self):
|
||||
"""
|
||||
Called at system exit to clean up any running presentations and
|
||||
close the application
|
||||
"""
|
||||
log.debug(u'Kill')
|
||||
self.close_presentation()
|
||||
|
||||
def load_presentation(self, presentation):
|
||||
def load_presentation(self):
|
||||
"""
|
||||
Called when a presentation is added to the SlideController.
|
||||
Loads the presentation and starts it
|
||||
|
@ -190,16 +216,29 @@ class PresentationController(object):
|
|||
"""
|
||||
pass
|
||||
|
||||
def presentation_deleted(self):
|
||||
"""
|
||||
Cleans up/deletes any controller specific files created for
|
||||
a file, e.g. thumbnails
|
||||
"""
|
||||
shutil.rmtree(self.thumbnailpath)
|
||||
|
||||
def store_filename(self, presentation):
|
||||
"""
|
||||
Set properties for the filename and thumbnail paths
|
||||
"""
|
||||
self.filepath = presentation
|
||||
self.filename = os.path.split(presentation)[1]
|
||||
self.thumbnailpath = os.path.join(self.thumbnailroot, self.filename)
|
||||
self.filename = self.get_file_name(presentation)
|
||||
self.thumbnailpath = self.get_thumbnail_path(presentation)
|
||||
if not os.path.isdir(self.thumbnailpath):
|
||||
os.mkdir(self.thumbnailpath)
|
||||
|
||||
def get_file_name(self, presentation):
|
||||
return os.path.split(presentation)[1]
|
||||
|
||||
def get_thumbnail_path(self, presentation):
|
||||
return os.path.join(self.controller.thumbnailroot, self.get_file_name(presentation))
|
||||
|
||||
def check_thumbnails(self):
|
||||
"""
|
||||
Returns true if the thumbnail images look to exist and are more
|
||||
|
@ -217,10 +256,10 @@ class PresentationController(object):
|
|||
Close presentation and clean up objects
|
||||
Triggered by new object being added to SlideController
|
||||
"""
|
||||
pass
|
||||
self.controller.delete_doc(self)
|
||||
|
||||
def is_active(self):
|
||||
"""
|
||||
"""
|
||||
Returns True if a presentation is currently running
|
||||
"""
|
||||
return False
|
||||
|
@ -243,6 +282,12 @@ class PresentationController(object):
|
|||
"""
|
||||
pass
|
||||
|
||||
def is_blank(self):
|
||||
"""
|
||||
Returns true if screen is blank
|
||||
"""
|
||||
return False
|
||||
|
||||
def stop_presentation(self):
|
||||
"""
|
||||
Stops the presentation, removing it from the output display
|
||||
|
@ -313,4 +358,22 @@ class PresentationController(object):
|
|||
else:
|
||||
prefix = u'preview'
|
||||
Receiver.send_message(u'%s_slidecontroller_change' % prefix,
|
||||
self.slidenumber - 1)
|
||||
self.slidenumber - 1)
|
||||
|
||||
def get_slide_text(self, slide_no):
|
||||
"""
|
||||
Returns the text on the slide
|
||||
|
||||
``slide_no``
|
||||
The slide the text is required for, starting at 1
|
||||
"""
|
||||
return ''
|
||||
|
||||
def get_slide_notes(self, slide_no):
|
||||
"""
|
||||
Returns the text on the slide
|
||||
|
||||
``slide_no``
|
||||
The slide the notes are required for, starting at 1
|
||||
"""
|
||||
return ''
|
||||
|
|
|
@ -51,17 +51,10 @@ class PresentationTab(SettingsTab):
|
|||
self.PresentationLeftLayout.setMargin(0)
|
||||
self.VerseDisplayGroupBox = QtGui.QGroupBox(self)
|
||||
self.VerseDisplayGroupBox.setObjectName(u'VerseDisplayGroupBox')
|
||||
self.VerseDisplayLayout = QtGui.QGridLayout(self.VerseDisplayGroupBox)
|
||||
self.VerseDisplayLayout = QtGui.QVBoxLayout(self.VerseDisplayGroupBox)
|
||||
self.VerseDisplayLayout.setMargin(8)
|
||||
self.VerseDisplayLayout.setObjectName(u'VerseDisplayLayout')
|
||||
self.VerseTypeWidget = QtGui.QWidget(self.VerseDisplayGroupBox)
|
||||
self.VerseTypeWidget.setObjectName(u'VerseTypeWidget')
|
||||
self.VerseTypeLayout = QtGui.QHBoxLayout(self.VerseTypeWidget)
|
||||
self.VerseTypeLayout.setSpacing(8)
|
||||
self.VerseTypeLayout.setMargin(0)
|
||||
self.VerseTypeLayout.setObjectName(u'VerseTypeLayout')
|
||||
self.PresenterCheckboxes = {}
|
||||
index = 0
|
||||
for key in self.controllers:
|
||||
controller = self.controllers[key]
|
||||
checkbox = QtGui.QCheckBox(self.VerseDisplayGroupBox)
|
||||
|
@ -69,8 +62,7 @@ class PresentationTab(SettingsTab):
|
|||
checkbox.setEnabled(controller.available)
|
||||
checkbox.setObjectName(controller.name + u'CheckBox')
|
||||
self.PresenterCheckboxes[controller.name] = checkbox
|
||||
index = index + 1
|
||||
self.VerseDisplayLayout.addWidget(checkbox, index, 0, 1, 1)
|
||||
self.VerseDisplayLayout.addWidget(checkbox)
|
||||
self.PresentationThemeWidget = QtGui.QWidget(self.VerseDisplayGroupBox)
|
||||
self.PresentationThemeWidget.setObjectName(u'PresentationThemeWidget')
|
||||
self.PresentationThemeLayout = QtGui.QHBoxLayout(
|
||||
|
@ -96,6 +88,7 @@ class PresentationTab(SettingsTab):
|
|||
self.PresentationLayout.addWidget(self.PresentationRightWidget)
|
||||
|
||||
def retranslateUi(self):
|
||||
self.VerseDisplayGroupBox.setTitle(self.trUtf8('Available Controllers'))
|
||||
for key in self.controllers:
|
||||
controller = self.controllers[key]
|
||||
checkbox = self.PresenterCheckboxes[controller.name]
|
||||
|
@ -115,4 +108,4 @@ class PresentationTab(SettingsTab):
|
|||
controller = self.controllers[key]
|
||||
checkbox = self.PresenterCheckboxes[controller.name]
|
||||
self.config.set_config(
|
||||
controller.name, unicode(checkbox.checkState()))
|
||||
controller.name, unicode(checkbox.checkState()))
|
||||
|
|
|
@ -26,20 +26,21 @@
|
|||
import os
|
||||
import logging
|
||||
|
||||
from openlp.core.lib import Plugin, build_icon
|
||||
from openlp.core.lib import Plugin, build_icon, Receiver, PluginStatus
|
||||
from openlp.plugins.presentations.lib import *
|
||||
|
||||
class PresentationPlugin(Plugin):
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
global log
|
||||
class PresentationPlugin(Plugin):
|
||||
log = logging.getLogger(u'PresentationPlugin')
|
||||
|
||||
def __init__(self, plugin_helpers):
|
||||
log.debug(u'Initialised')
|
||||
self.controllers = {}
|
||||
Plugin.__init__(self, u'Presentations', u'1.9.0', plugin_helpers)
|
||||
Plugin.__init__(self, u'Presentations', u'1.9.1', plugin_helpers)
|
||||
self.weight = -8
|
||||
self.icon = build_icon(u':/media/media_presentation.png')
|
||||
self.status = PluginStatus.Active
|
||||
|
||||
def get_settings_tab(self):
|
||||
"""
|
||||
|
@ -51,6 +52,12 @@ class PresentationPlugin(Plugin):
|
|||
log.info(u'Presentations Initialising')
|
||||
Plugin.initialise(self)
|
||||
self.insert_toolbox_item()
|
||||
presentation_types = []
|
||||
for controller in self.controllers:
|
||||
if self.controllers[controller].enabled:
|
||||
presentation_types.append({u'%s' % controller : self.controllers[controller].supports})
|
||||
Receiver.send_message(
|
||||
u'presentation types', presentation_types)
|
||||
|
||||
def finalise(self):
|
||||
log.info(u'Plugin Finalise')
|
||||
|
@ -96,7 +103,7 @@ class PresentationPlugin(Plugin):
|
|||
self.registerControllers(controller)
|
||||
if controller.enabled:
|
||||
controller.start_process()
|
||||
if len(self.controllers) > 0:
|
||||
if self.controllers:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
@ -106,4 +113,4 @@ class PresentationPlugin(Plugin):
|
|||
'the ability to show presentations using a number of different '
|
||||
'programs. The choice of available presentation programs is '
|
||||
'available to the user in a drop down box.')
|
||||
return about_text
|
||||
return about_text
|
||||
|
|
|
@ -28,7 +28,6 @@ import socket
|
|||
import sys
|
||||
from optparse import OptionParser
|
||||
|
||||
|
||||
def sendData(options, message):
|
||||
addr = (options.address, options.port)
|
||||
try:
|
||||
|
@ -47,34 +46,23 @@ def main():
|
|||
parser.add_option("-v", "--verbose",
|
||||
action="store_true", dest="verbose", default=True,
|
||||
help="make lots of noise [%default]")
|
||||
parser.add_option("-p", "--port",
|
||||
default=4316,
|
||||
parser.add_option("-p", "--port", default=4316,
|
||||
help="IP Port number %default ")
|
||||
parser.add_option("-a", "--address",
|
||||
help="Recipient address ")
|
||||
parser.add_option("-e", "--event",
|
||||
default=u'Alert',
|
||||
help="Action to be undertaken")
|
||||
parser.add_option("-m", "--message",
|
||||
help="Message to be passed for the action")
|
||||
parser.add_option("-n", "--slidenext",
|
||||
help="Trigger the next slide")
|
||||
|
||||
(options, args) = parser.parse_args()
|
||||
if len(args) > 0:
|
||||
if args:
|
||||
parser.print_help()
|
||||
parser.error("incorrect number of arguments")
|
||||
elif options.message is None:
|
||||
parser.print_help()
|
||||
parser.error("No message passed")
|
||||
elif options.address is None:
|
||||
parser.print_help()
|
||||
parser.error("IP address missing")
|
||||
elif options.slidenext:
|
||||
options.event = u'next_slide'
|
||||
options.message = u''
|
||||
text = format_message(options)
|
||||
sendData(options, text)
|
||||
elif options.message is None:
|
||||
parser.print_help()
|
||||
parser.error("No message passed")
|
||||
else:
|
||||
text = format_message(options)
|
||||
sendData(options, text)
|
|
@ -30,14 +30,13 @@ from PyQt4 import QtNetwork, QtCore
|
|||
from openlp.core.lib import Plugin, Receiver
|
||||
from openlp.plugins.remotes.lib import RemoteTab
|
||||
|
||||
class RemotesPlugin(Plugin):
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
global log
|
||||
log = logging.getLogger(u'RemotesPlugin')
|
||||
class RemotesPlugin(Plugin):
|
||||
log.info(u'Remote Plugin loaded')
|
||||
|
||||
def __init__(self, plugin_helpers):
|
||||
Plugin.__init__(self, u'Remotes', u'1.9.0', plugin_helpers)
|
||||
Plugin.__init__(self, u'Remotes', u'1.9.1', plugin_helpers)
|
||||
self.weight = -1
|
||||
self.server = None
|
||||
|
||||
|
@ -83,4 +82,4 @@ class RemotesPlugin(Plugin):
|
|||
'provides the ability to send messages to a running version of '
|
||||
'openlp on a different computer.<br>The Primary use for this '
|
||||
'would be to send alerts from a creche')
|
||||
return about_text
|
||||
return about_text
|
||||
|
|
|
@ -33,13 +33,13 @@ from openlp.plugins.songs.forms import EditVerseForm
|
|||
from openlp.plugins.songs.lib.models import Song
|
||||
from editsongdialog import Ui_EditSongDialog
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
|
||||
"""
|
||||
Class to manage the editing of a song
|
||||
"""
|
||||
global log
|
||||
log = logging.getLogger(u'EditSongForm')
|
||||
log.info(u'Song Editor loaded')
|
||||
log.info(u'%s EditSongForm loaded', __name__)
|
||||
|
||||
def __init__(self, songmanager, parent=None):
|
||||
"""
|
||||
|
@ -169,6 +169,8 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
|
|||
self.loadAuthors()
|
||||
self.loadTopics()
|
||||
self.loadBooks()
|
||||
#it's a new song to preview is not possible
|
||||
self.previewButton.setVisible(False)
|
||||
|
||||
def loadSong(self, id, preview):
|
||||
log.debug(u'Load Song')
|
||||
|
@ -316,13 +318,13 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
|
|||
|
||||
def onVerseAddButtonClicked(self):
|
||||
self.verse_form.setVerse(u'', self.VerseListWidget.count() + 1, True)
|
||||
self.verse_form.exec_()
|
||||
afterText, verse, subVerse = self.verse_form.getVerse()
|
||||
data = u'%s:%s' %(verse, subVerse)
|
||||
item = QtGui.QListWidgetItem(afterText)
|
||||
item.setData(QtCore.Qt.UserRole, QtCore.QVariant(data))
|
||||
item.setText(afterText)
|
||||
self.VerseListWidget.addItem(item)
|
||||
if self.verse_form.exec_():
|
||||
afterText, verse, subVerse = self.verse_form.getVerse()
|
||||
data = u'%s:%s' %(verse, subVerse)
|
||||
item = QtGui.QListWidgetItem(afterText)
|
||||
item.setData(QtCore.Qt.UserRole, QtCore.QVariant(data))
|
||||
item.setText(afterText)
|
||||
self.VerseListWidget.addItem(item)
|
||||
|
||||
def onVerseEditButtonClicked(self):
|
||||
item = self.VerseListWidget.currentItem()
|
||||
|
@ -331,25 +333,25 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
|
|||
verseId = unicode((item.data(QtCore.Qt.UserRole)).toString())
|
||||
self.verse_form.setVerse(tempText, \
|
||||
self.VerseListWidget.count(), True, verseId)
|
||||
self.verse_form.exec_()
|
||||
afterText, verse, subVerse = self.verse_form.getVerse()
|
||||
data = u'%s:%s' %(verse, subVerse)
|
||||
item.setData(QtCore.Qt.UserRole, QtCore.QVariant(data))
|
||||
item.setText(afterText)
|
||||
#number of lines has change so repaint the list moving the data
|
||||
if len(tempText.split(u'\n')) != len(afterText.split(u'\n')):
|
||||
tempList = {}
|
||||
tempId = {}
|
||||
for row in range(0, self.VerseListWidget.count()):
|
||||
tempList[row] = self.VerseListWidget.item(row).text()
|
||||
tempId[row] = self.VerseListWidget.item(row).\
|
||||
data(QtCore.Qt.UserRole)
|
||||
self.VerseListWidget.clear()
|
||||
for row in range (0, len(tempList)):
|
||||
item = QtGui.QListWidgetItem(tempList[row])
|
||||
item.setData(QtCore.Qt.UserRole, tempId[row])
|
||||
self.VerseListWidget.addItem(item)
|
||||
self.VerseListWidget.repaint()
|
||||
if self.verse_form.exec_():
|
||||
afterText, verse, subVerse = self.verse_form.getVerse()
|
||||
data = u'%s:%s' %(verse, subVerse)
|
||||
item.setData(QtCore.Qt.UserRole, QtCore.QVariant(data))
|
||||
item.setText(afterText)
|
||||
#number of lines has change so repaint the list moving the data
|
||||
if len(tempText.split(u'\n')) != len(afterText.split(u'\n')):
|
||||
tempList = {}
|
||||
tempId = {}
|
||||
for row in range(0, self.VerseListWidget.count()):
|
||||
tempList[row] = self.VerseListWidget.item(row).text()
|
||||
tempId[row] = self.VerseListWidget.item(row).\
|
||||
data(QtCore.Qt.UserRole)
|
||||
self.VerseListWidget.clear()
|
||||
for row in range (0, len(tempList)):
|
||||
item = QtGui.QListWidgetItem(tempList[row])
|
||||
item.setData(QtCore.Qt.UserRole, tempId[row])
|
||||
self.VerseListWidget.addItem(item)
|
||||
self.VerseListWidget.repaint()
|
||||
self.VerseEditButton.setEnabled(False)
|
||||
self.VerseDeleteButton.setEnabled(False)
|
||||
|
||||
|
@ -410,7 +412,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
|
|||
self.AuthorsListView.setFocus()
|
||||
#split the verse list by space and mark lower case for testing
|
||||
for verse in unicode(self.VerseOrderEdit.text()).lower().split(u' '):
|
||||
if len(verse) == 2:
|
||||
if len(verse) > 1:
|
||||
if verse[0:1] == u'v' and verse[1:].isdigit():
|
||||
pass
|
||||
else:
|
||||
|
@ -533,4 +535,4 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
|
|||
self.song.search_title = self.song.search_title.replace(u'{', u'')
|
||||
self.song.search_title = self.song.search_title.replace(u'}', u'')
|
||||
self.song.search_title = self.song.search_title.replace(u'?', u'')
|
||||
self.song.search_title = unicode(self.song.search_title)
|
||||
self.song.search_title = unicode(self.song.search_title)
|
||||
|
|
|
@ -1,113 +1,129 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
|
||||
|
||||
# Form implementation generated from reading ui file 'editversedialog.ui'
|
||||
#
|
||||
# Created: Wed Dec 2 08:14:47 2009
|
||||
# by: PyQt4 UI code generator 4.6.2
|
||||
#
|
||||
# WARNING! All changes made in this file will be lost!
|
||||
###############################################################################
|
||||
# OpenLP - Open Source Lyrics Projection #
|
||||
# --------------------------------------------------------------------------- #
|
||||
# Copyright (c) 2008-2010 Raoul Snyman #
|
||||
# Portions copyright (c) 2008-2010 Tim Bentley, Jonathan Corwin, Michael #
|
||||
# Gorven, Scott Guerrieri, Maikel Stuivenberg, Martin Thompson, Jon Tibble, #
|
||||
# Carsten Tinggaard #
|
||||
# --------------------------------------------------------------------------- #
|
||||
# This program is free software; you can redistribute it and/or modify it #
|
||||
# under the terms of the GNU General Public License as published by the Free #
|
||||
# Software Foundation; version 2 of the License. #
|
||||
# #
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT #
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
|
||||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
|
||||
# more details. #
|
||||
# #
|
||||
# You should have received a copy of the GNU General Public License along #
|
||||
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
|
||||
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
||||
###############################################################################
|
||||
|
||||
from PyQt4 import QtCore, QtGui
|
||||
|
||||
class Ui_EditVerseDialog(object):
|
||||
def setupUi(self, EditVerseDialog):
|
||||
EditVerseDialog.setObjectName("EditVerseDialog")
|
||||
EditVerseDialog.setObjectName(u'EditVerseDialog')
|
||||
EditVerseDialog.resize(500, 521)
|
||||
EditVerseDialog.setModal(True)
|
||||
self.layoutWidget = QtGui.QWidget(EditVerseDialog)
|
||||
self.layoutWidget.setGeometry(QtCore.QRect(11, 1, 471, 491))
|
||||
self.layoutWidget.setObjectName("layoutWidget")
|
||||
self.layoutWidget.setObjectName(u'layoutWidget')
|
||||
self.verticalLayout_3 = QtGui.QVBoxLayout(self.layoutWidget)
|
||||
self.verticalLayout_3.setObjectName("verticalLayout_3")
|
||||
self.verticalLayout_3.setObjectName(u'verticalLayout_3')
|
||||
self.horizontalLayout = QtGui.QHBoxLayout()
|
||||
self.horizontalLayout.setObjectName("horizontalLayout")
|
||||
self.horizontalLayout.setObjectName(u'horizontalLayout')
|
||||
self.verticalLayout = QtGui.QVBoxLayout()
|
||||
self.verticalLayout.setObjectName("verticalLayout")
|
||||
self.verticalLayout.setObjectName(u'verticalLayout')
|
||||
self.VerseTypeLabel = QtGui.QLabel(self.layoutWidget)
|
||||
self.VerseTypeLabel.setTextFormat(QtCore.Qt.PlainText)
|
||||
self.VerseTypeLabel.setAlignment(QtCore.Qt.AlignCenter)
|
||||
self.VerseTypeLabel.setObjectName("VerseTypeLabel")
|
||||
self.VerseTypeLabel.setObjectName(u'VerseTypeLabel')
|
||||
self.verticalLayout.addWidget(self.VerseTypeLabel)
|
||||
self.VerseListComboBox = QtGui.QComboBox(self.layoutWidget)
|
||||
self.VerseListComboBox.setObjectName("VerseListComboBox")
|
||||
self.VerseListComboBox.addItem("")
|
||||
self.VerseListComboBox.addItem("")
|
||||
self.VerseListComboBox.addItem("")
|
||||
self.VerseListComboBox.addItem("")
|
||||
self.VerseListComboBox.addItem("")
|
||||
self.VerseListComboBox.addItem("")
|
||||
self.VerseListComboBox.addItem("")
|
||||
self.VerseListComboBox.setObjectName(u'VerseListComboBox')
|
||||
self.VerseListComboBox.addItem(u'')
|
||||
self.VerseListComboBox.addItem(u'')
|
||||
self.VerseListComboBox.addItem(u'')
|
||||
self.VerseListComboBox.addItem(u'')
|
||||
self.VerseListComboBox.addItem(u'')
|
||||
self.VerseListComboBox.addItem(u'')
|
||||
self.VerseListComboBox.addItem(u'')
|
||||
self.verticalLayout.addWidget(self.VerseListComboBox)
|
||||
self.horizontalLayout.addLayout(self.verticalLayout)
|
||||
self.verticalLayout_2 = QtGui.QVBoxLayout()
|
||||
self.verticalLayout_2.setObjectName("verticalLayout_2")
|
||||
self.verticalLayout_2.setObjectName(u'verticalLayout_2')
|
||||
self.VerseNumberLabel = QtGui.QLabel(self.layoutWidget)
|
||||
self.VerseNumberLabel.setAlignment(QtCore.Qt.AlignCenter)
|
||||
self.VerseNumberLabel.setObjectName("VerseNumberLabel")
|
||||
self.VerseNumberLabel.setObjectName(u'VerseNumberLabel')
|
||||
self.verticalLayout_2.addWidget(self.VerseNumberLabel)
|
||||
self.SubVerseListComboBox = QtGui.QComboBox(self.layoutWidget)
|
||||
self.SubVerseListComboBox.setObjectName("SubVerseListComboBox")
|
||||
self.SubVerseListComboBox.setObjectName(u'SubVerseListComboBox')
|
||||
self.verticalLayout_2.addWidget(self.SubVerseListComboBox)
|
||||
self.horizontalLayout.addLayout(self.verticalLayout_2)
|
||||
self.verticalLayout_3.addLayout(self.horizontalLayout)
|
||||
self.VerseTextEdit = QtGui.QTextEdit(self.layoutWidget)
|
||||
self.VerseTextEdit.setAcceptRichText(False)
|
||||
self.VerseTextEdit.setObjectName("VerseTextEdit")
|
||||
self.VerseTextEdit.setObjectName(u'VerseTextEdit')
|
||||
self.verticalLayout_3.addWidget(self.VerseTextEdit)
|
||||
self.horizontalLayout_2 = QtGui.QHBoxLayout()
|
||||
self.horizontalLayout_2.setObjectName("horizontalLayout_2")
|
||||
self.horizontalLayout_2.setObjectName(u'horizontalLayout_2')
|
||||
self.addBridge = QtGui.QPushButton(self.layoutWidget)
|
||||
self.addBridge.setObjectName("addBridge")
|
||||
self.addBridge.setObjectName(u'addBridge')
|
||||
self.horizontalLayout_2.addWidget(self.addBridge)
|
||||
self.addVerse = QtGui.QPushButton(self.layoutWidget)
|
||||
self.addVerse.setObjectName("addVerse")
|
||||
self.addVerse.setObjectName(u'addVerse')
|
||||
self.horizontalLayout_2.addWidget(self.addVerse)
|
||||
self.addChorus = QtGui.QPushButton(self.layoutWidget)
|
||||
self.addChorus.setObjectName("addChorus")
|
||||
self.addChorus.setObjectName(u'addChorus')
|
||||
self.horizontalLayout_2.addWidget(self.addChorus)
|
||||
self.verticalLayout_3.addLayout(self.horizontalLayout_2)
|
||||
self.horizontalLayout_3 = QtGui.QHBoxLayout()
|
||||
self.horizontalLayout_3.setObjectName("horizontalLayout_3")
|
||||
self.horizontalLayout_3.setObjectName(u'horizontalLayout_3')
|
||||
self.addPreChorus = QtGui.QPushButton(self.layoutWidget)
|
||||
self.addPreChorus.setObjectName("addPreChorus")
|
||||
self.addPreChorus.setObjectName(u'addPreChorus')
|
||||
self.horizontalLayout_3.addWidget(self.addPreChorus)
|
||||
self.addIntro = QtGui.QPushButton(self.layoutWidget)
|
||||
self.addIntro.setObjectName("addIntro")
|
||||
self.addIntro.setObjectName(u'addIntro')
|
||||
self.horizontalLayout_3.addWidget(self.addIntro)
|
||||
self.addOther = QtGui.QPushButton(self.layoutWidget)
|
||||
self.addOther.setObjectName("addOther")
|
||||
self.addOther.setObjectName(u'addOther')
|
||||
self.horizontalLayout_3.addWidget(self.addOther)
|
||||
self.addEnding = QtGui.QPushButton(self.layoutWidget)
|
||||
self.addEnding.setObjectName("addEnding")
|
||||
self.addEnding.setObjectName(u'addEnding')
|
||||
self.horizontalLayout_3.addWidget(self.addEnding)
|
||||
self.verticalLayout_3.addLayout(self.horizontalLayout_3)
|
||||
self.ButtonBox = QtGui.QDialogButtonBox(self.layoutWidget)
|
||||
self.ButtonBox.setOrientation(QtCore.Qt.Horizontal)
|
||||
self.ButtonBox.setStandardButtons(QtGui.QDialogButtonBox.Cancel|QtGui.QDialogButtonBox.Save)
|
||||
self.ButtonBox.setObjectName("ButtonBox")
|
||||
self.ButtonBox.setObjectName(u'ButtonBox')
|
||||
self.verticalLayout_3.addWidget(self.ButtonBox)
|
||||
|
||||
self.retranslateUi(EditVerseDialog)
|
||||
QtCore.QObject.connect(self.ButtonBox, QtCore.SIGNAL("accepted()"), EditVerseDialog.accept)
|
||||
QtCore.QObject.connect(self.ButtonBox, QtCore.SIGNAL("rejected()"), EditVerseDialog.reject)
|
||||
QtCore.QObject.connect(self.ButtonBox, QtCore.SIGNAL(u'accepted()'), EditVerseDialog.accept)
|
||||
QtCore.QObject.connect(self.ButtonBox, QtCore.SIGNAL(u'rejected()'), EditVerseDialog.reject)
|
||||
QtCore.QMetaObject.connectSlotsByName(EditVerseDialog)
|
||||
|
||||
def retranslateUi(self, EditVerseDialog):
|
||||
EditVerseDialog.setWindowTitle(QtGui.QApplication.translate("EditVerseDialog", "Edit Verse", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.VerseTypeLabel.setText(QtGui.QApplication.translate("EditVerseDialog", "Verse Type", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.VerseListComboBox.setItemText(0, QtGui.QApplication.translate("EditVerseDialog", "Intro", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.VerseListComboBox.setItemText(1, QtGui.QApplication.translate("EditVerseDialog", "Verse", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.VerseListComboBox.setItemText(2, QtGui.QApplication.translate("EditVerseDialog", "Pre-Chorus", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.VerseListComboBox.setItemText(3, QtGui.QApplication.translate("EditVerseDialog", "Chorus", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.VerseListComboBox.setItemText(4, QtGui.QApplication.translate("EditVerseDialog", "Bridge", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.VerseListComboBox.setItemText(5, QtGui.QApplication.translate("EditVerseDialog", "Ending", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.VerseListComboBox.setItemText(6, QtGui.QApplication.translate("EditVerseDialog", "Other", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.VerseNumberLabel.setText(QtGui.QApplication.translate("EditVerseDialog", "Number", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.addBridge.setText(QtGui.QApplication.translate("EditVerseDialog", "Bridge", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.addVerse.setText(QtGui.QApplication.translate("EditVerseDialog", "Verse", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.addChorus.setText(QtGui.QApplication.translate("EditVerseDialog", "Chorus", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.addPreChorus.setText(QtGui.QApplication.translate("EditVerseDialog", "Pre-Chorus", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.addIntro.setText(QtGui.QApplication.translate("EditVerseDialog", "Intro", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.addOther.setText(QtGui.QApplication.translate("EditVerseDialog", "Other", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.addEnding.setText(QtGui.QApplication.translate("EditVerseDialog", "Ending", None, QtGui.QApplication.UnicodeUTF8))
|
||||
EditVerseDialog.setWindowTitle(self.trUtf8('Edit Verse'))
|
||||
self.VerseTypeLabel.setText(self.trUtf8('Verse Type'))
|
||||
self.VerseListComboBox.setItemText(0, self.trUtf8('Intro'))
|
||||
self.VerseListComboBox.setItemText(1, self.trUtf8('Verse'))
|
||||
self.VerseListComboBox.setItemText(2, self.trUtf8('Pre-Chorus'))
|
||||
self.VerseListComboBox.setItemText(3, self.trUtf8('Chorus'))
|
||||
self.VerseListComboBox.setItemText(4, self.trUtf8('Bridge'))
|
||||
self.VerseListComboBox.setItemText(5, self.trUtf8('Ending'))
|
||||
self.VerseListComboBox.setItemText(6, self.trUtf8('Other'))
|
||||
self.VerseNumberLabel.setText(self.trUtf8('Number'))
|
||||
self.addBridge.setText(self.trUtf8('Bridge'))
|
||||
self.addVerse.setText(self.trUtf8('Verse'))
|
||||
self.addChorus.setText(self.trUtf8('Chorus'))
|
||||
self.addPreChorus.setText(self.trUtf8('Pre-Chorus'))
|
||||
self.addIntro.setText(self.trUtf8('Intro'))
|
||||
self.addOther.setText(self.trUtf8('Other'))
|
||||
self.addEnding.setText(self.trUtf8('Ending'))
|
||||
|
||||
|
|
|
@ -77,6 +77,8 @@ class EditVerseForm(QtGui.QDialog, Ui_EditVerseDialog):
|
|||
def setVerse(self, text, verseCount=0, single=False, tag=u'Verse:1'):
|
||||
posVerse = 0
|
||||
posSub = 0
|
||||
if len(text) == 0 and not single:
|
||||
text = u'---[Verse:1]---\n'
|
||||
if single:
|
||||
id = tag.split(u':')
|
||||
posVerse = self.VerseListComboBox.findText(id[0], QtCore.Qt.MatchExactly)
|
||||
|
@ -112,6 +114,7 @@ class EditVerseForm(QtGui.QDialog, Ui_EditVerseDialog):
|
|||
self.VerseTextEdit.setPlainText(text)
|
||||
self.VerseTextEdit.setFocus(QtCore.Qt.OtherFocusReason)
|
||||
self.onVerseComboChanged(0)
|
||||
self.VerseTextEdit.moveCursor(QtGui.QTextCursor.Down)
|
||||
|
||||
def getVerse(self):
|
||||
return self.VerseTextEdit.toPlainText(), \
|
||||
|
@ -119,11 +122,14 @@ class EditVerseForm(QtGui.QDialog, Ui_EditVerseDialog):
|
|||
unicode(self.SubVerseListComboBox.currentText())
|
||||
|
||||
def getVerseAll(self):
|
||||
return self.VerseTextEdit.toPlainText()
|
||||
text = self.VerseTextEdit.toPlainText()
|
||||
if not text.startsWith(u'---['):
|
||||
text = u'---[Verse:1]---\n%s' % text
|
||||
return text
|
||||
|
||||
def onVerseComboChanged(self, id):
|
||||
if unicode(self.VerseListComboBox.currentText()) == u'Verse':
|
||||
self.SubVerseListComboBox.setEnabled(True)
|
||||
else:
|
||||
self.SubVerseListComboBox.setEnabled(False)
|
||||
self.SubVerseListComboBox.setCurrentIndex(0)
|
||||
self.SubVerseListComboBox.setCurrentIndex(0)
|
||||
|
|
|
@ -51,10 +51,10 @@ class Ui_SongMaintenanceDialog(object):
|
|||
self.TypeListWidget.sizePolicy().hasHeightForWidth())
|
||||
self.TypeListWidget.setSizePolicy(sizePolicy)
|
||||
self.TypeListWidget.setViewMode(QtGui.QListView.IconMode)
|
||||
self.TypeListWidget.setIconSize(QtCore.QSize(112, 100));
|
||||
self.TypeListWidget.setMovement(QtGui.QListView.Static);
|
||||
self.TypeListWidget.setMaximumWidth(118);
|
||||
self.TypeListWidget.setSpacing(0);
|
||||
self.TypeListWidget.setIconSize(QtCore.QSize(112, 100))
|
||||
self.TypeListWidget.setMovement(QtGui.QListView.Static)
|
||||
self.TypeListWidget.setMaximumWidth(118)
|
||||
self.TypeListWidget.setSpacing(0)
|
||||
self.TypeListWidget.setSortingEnabled(False)
|
||||
self.TypeListWidget.setUniformItemSizes(True)
|
||||
self.TypeListWidget.setObjectName(u'TypeListWidget')
|
||||
|
|
|
@ -139,7 +139,7 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog):
|
|||
else:
|
||||
QtGui.QMessageBox.critical(
|
||||
self, self.trUtf8('Error'),
|
||||
self.trUtf8('Couldn\'t add your author!'),
|
||||
self.trUtf8('Couldn\'t add your author.'),
|
||||
QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Ok))
|
||||
|
||||
def onTopicAddButtonClick(self):
|
||||
|
@ -150,7 +150,7 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog):
|
|||
else:
|
||||
QtGui.QMessageBox.critical(
|
||||
self, self.trUtf8('Error'),
|
||||
self.trUtf8('Couldn\'t add your topic!'),
|
||||
self.trUtf8('Couldn\'t add your topic.'),
|
||||
QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Ok))
|
||||
|
||||
def onBookAddButtonClick(self):
|
||||
|
@ -162,7 +162,7 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog):
|
|||
else:
|
||||
QtGui.QMessageBox.critical(
|
||||
self, self.trUtf8('Error'),
|
||||
self.trUtf8('Couldn\'t add your book!'),
|
||||
self.trUtf8('Couldn\'t add your book.'),
|
||||
QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Ok))
|
||||
|
||||
def onAuthorEditButtonClick(self):
|
||||
|
@ -182,7 +182,7 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog):
|
|||
else:
|
||||
QtGui.QMessageBox.critical(
|
||||
self, self.trUtf8('Error'),
|
||||
self.trUtf8('Couldn\'t save your author!'),
|
||||
self.trUtf8('Couldn\'t save your author.'),
|
||||
QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Ok))
|
||||
|
||||
def onTopicEditButtonClick(self):
|
||||
|
@ -197,7 +197,7 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog):
|
|||
else:
|
||||
QtGui.QMessageBox.critical(
|
||||
self, self.trUtf8('Error'),
|
||||
self.trUtf8('Couldn\'t save your topic!'),
|
||||
self.trUtf8('Couldn\'t save your topic.'),
|
||||
QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Ok))
|
||||
|
||||
def onBookEditButtonClick(self):
|
||||
|
@ -214,7 +214,7 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog):
|
|||
else:
|
||||
QtGui.QMessageBox.critical(
|
||||
self, self.trUtf8('Error'),
|
||||
self.trUtf8('Couldn\'t save your book!'),
|
||||
self.trUtf8('Couldn\'t save your book.'),
|
||||
QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Ok))
|
||||
|
||||
def onAuthorDeleteButtonClick(self):
|
||||
|
@ -227,7 +227,7 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog):
|
|||
self.trUtf8('Delete Author'),
|
||||
self.trUtf8('Are you sure you want to delete the selected author?'),
|
||||
self.trUtf8('This author can\'t be deleted, they are currently '
|
||||
'assigned to at least one song!'),
|
||||
'assigned to at least one song.'),
|
||||
self.trUtf8('No author selected!'))
|
||||
|
||||
def onTopicDeleteButtonClick(self):
|
||||
|
@ -240,7 +240,7 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog):
|
|||
self.trUtf8('Delete Topic'),
|
||||
self.trUtf8('Are you sure you want to delete the selected topic?'),
|
||||
self.trUtf8('This topic can\'t be deleted, it is currently '
|
||||
'assigned to at least one song!'),
|
||||
'assigned to at least one song.'),
|
||||
self.trUtf8('No topic selected!'))
|
||||
|
||||
def onBookDeleteButtonClick(self):
|
||||
|
@ -253,5 +253,5 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog):
|
|||
self.trUtf8('Delete Book'),
|
||||
self.trUtf8('Are you sure you want to delete the selected book?'),
|
||||
self.trUtf8('This book can\'t be deleted, it is currently '
|
||||
'assigned to at least one song!'),
|
||||
self.trUtf8('No book selected!'))
|
||||
'assigned to at least one song.'),
|
||||
self.trUtf8('No book selected!'))
|
||||
|
|
|
@ -28,14 +28,13 @@ import logging
|
|||
from openlp.plugins.songs.lib.models import init_models, metadata, Song, \
|
||||
Author, Topic, Book
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
class SongManager():
|
||||
"""
|
||||
The Song Manager provides a central location for all database code. This
|
||||
class takes care of connecting to the database and running all the queries.
|
||||
"""
|
||||
|
||||
global log
|
||||
log = logging.getLogger(u'SongManager')
|
||||
log.info(u'Song manager loaded')
|
||||
|
||||
def __init__(self, config):
|
||||
|
@ -238,3 +237,6 @@ class SongManager():
|
|||
self.session.rollback()
|
||||
log.exception(u'Could not delete book from song database')
|
||||
return False
|
||||
|
||||
def get_songs_for_theme(self, theme):
|
||||
return self.session.query(Song).filter(Song.theme_name == theme).all()
|
||||
|
|
|
@ -31,6 +31,8 @@ from openlp.core.lib import MediaManagerItem, SongXMLParser, \
|
|||
BaseListWithDnD, Receiver, str_to_bool
|
||||
from openlp.plugins.songs.forms import EditSongForm, SongMaintenanceForm
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
class SongListView(BaseListWithDnD):
|
||||
def __init__(self, parent=None):
|
||||
self.PluginName = u'Songs'
|
||||
|
@ -40,8 +42,6 @@ class SongMediaItem(MediaManagerItem):
|
|||
"""
|
||||
This is the custom media manager item for Songs.
|
||||
"""
|
||||
global log
|
||||
log = logging.getLogger(u'SongMediaItem')
|
||||
log.info(u'Song Media Item loaded')
|
||||
|
||||
def __init__(self, parent, icon, title):
|
||||
|
@ -185,8 +185,13 @@ class SongMediaItem(MediaManagerItem):
|
|||
if author_list != u'':
|
||||
author_list = author_list + u', '
|
||||
author_list = author_list + author.display_name
|
||||
song_detail = unicode(self.trUtf8('%s (%s)' % \
|
||||
(unicode(song.title), unicode(author_list))))
|
||||
if not isinstance(author_list, unicode):
|
||||
author_list = unicode(author_list, u'utf8')
|
||||
if isinstance(song.title, unicode):
|
||||
song_title = song.title
|
||||
else:
|
||||
song_title = unicode(song.title, u'utf8')
|
||||
song_detail = u'%s (%s)' % (song_title, author_list)
|
||||
song_name = QtGui.QListWidgetItem(song_detail)
|
||||
song_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(song.id))
|
||||
self.ListView.addItem(song_name)
|
||||
|
@ -285,6 +290,7 @@ class SongMediaItem(MediaManagerItem):
|
|||
item_id = (item.data(QtCore.Qt.UserRole)).toInt()[0]
|
||||
else:
|
||||
item_id = self.remoteSong
|
||||
service_item.autoPreviewAllowed = True
|
||||
song = self.parent.songmanager.get_song(item_id)
|
||||
service_item.theme = song.theme_name
|
||||
service_item.edit_enabled = True
|
||||
|
@ -305,7 +311,7 @@ class SongMediaItem(MediaManagerItem):
|
|||
for verse in verseList:
|
||||
if verse[1]:
|
||||
if verse[0][u'type'] == "Verse":
|
||||
if verse[0][u'label'][0] == order[1:]:
|
||||
if verse[0][u'label'] == order[1:]:
|
||||
verseTag = u'%s:%s' % \
|
||||
(verse[0][u'type'], verse[0][u'label'])
|
||||
service_item.add_from_text\
|
||||
|
@ -339,4 +345,4 @@ class SongMediaItem(MediaManagerItem):
|
|||
service_item.audit = [
|
||||
song.title, author_audit, song.copyright, song.ccli_number
|
||||
]
|
||||
return True
|
||||
return True
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue