This commit is contained in:
Tim Bentley 2009-09-21 19:59:35 +01:00
commit 38e0c1bc77
25 changed files with 503 additions and 325 deletions

View File

@ -30,7 +30,7 @@ from optparse import OptionParser
from PyQt4 import QtCore, QtGui
from openlp.core.lib import Receiver, str_to_bool
from openlp.core.resources import *
from openlp.core.resources import qInitResources
from openlp.core.ui import MainWindow, SplashScreen
from openlp.core.utils import ConfigHelper
@ -105,6 +105,8 @@ def main():
log.setLevel(logging.DEBUG)
else:
log.setLevel(logging.INFO)
# Initialise the resources
qInitResources()
# Now create and actually run the application.
app = OpenLP(sys.argv)
sys.exit(app.run())
@ -113,6 +115,4 @@ if __name__ == u'__main__':
"""
Instantiate and run the application.
"""
#import cProfile
#cProfile.run("main()", "profile.out")
main()

View File

@ -120,6 +120,7 @@ from serviceitem import ServiceItem
from serviceitem import ServiceType
from serviceitem import ServiceItem
from toolbar import OpenLPToolbar
from dockwidget import OpenLPDockWidget
from songxmlhandler import SongXMLBuilder, SongXMLParser
from themexmlhandler import ThemeXML
from renderer import Renderer

View File

@ -0,0 +1,53 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2009 Raoul Snyman #
# Portions copyright (c) 2008-2009 Martin Thompson, Tim Bentley, Carsten #
# Tinggaard, Jon Tibble, Jonathan Corwin, Maikel Stuivenberg, Scott Guerrieri #
# --------------------------------------------------------------------------- #
# 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 types
import logging
from PyQt4 import QtCore, QtGui
class OpenLPDockWidget(QtGui.QDockWidget):
"""
Custom DockWidget class to handle events
"""
def __init__(self, parent=None, name=None):
"""
Initialise the DockWidget
"""
QtGui.QDockWidget.__init__(self, parent)
self.parent = parent
if name is not None:
self.setObjectName(name)
self.log = logging.getLogger(u'OpenLPDockWidget')
self.log.debug(u'Init done')
def closeEvent(self, event):
self.parent.settingsmanager.setUIItemVisibility(
self.objectName(), False)
event.accept()
def resizeEvent(self, event):
if self.objectName() == u'MediaManagerDock':
if event.size().width() != event.oldSize().width():
self.parent.settingsmanager.setDockbarLeft(event.size().width())

View File

@ -80,6 +80,9 @@ class EventReceiver(QtCore.QObject):
``audit_live``
Sends live song audit requests to the audit component
``audit_changed``
Audit information may have changed
"""
global log
log = logging.getLogger(u'EventReceiver')

View File

@ -85,7 +85,8 @@ class PluginManager(object):
modulename = modulename[len(prefix) + 1:]
modulename = modulename.replace(os.path.sep, '.')
# import the modules
log.debug(u'Importing %s from %s. Depth %d', modulename, path, thisdepth)
log.debug(u'Importing %s from %s. Depth %d',
modulename, path, thisdepth)
try:
__import__(modulename, globals(), locals(), [])
except ImportError, e:
@ -131,8 +132,10 @@ class PluginManager(object):
if plugin.status == PluginStatus.Active:
media_manager_item = plugin.get_media_manager_item()
if media_manager_item is not None:
log.debug(u'Inserting media manager item from %s' % plugin.name)
mediatoolbox.addItem(media_manager_item, plugin.icon, media_manager_item.title)
log.debug(u'Inserting media manager item from %s' % \
plugin.name)
mediatoolbox.addItem(media_manager_item, plugin.icon,
media_manager_item.title)
def hook_settings_tabs(self, settingsform=None):
"""

View File

@ -31,7 +31,7 @@ from PyQt4 import QtGui, QtCore
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 a generated.
make sure it fits on the screen and if not extra frames are generated.
"""
global log
log = logging.getLogger(u'Renderer')
@ -153,18 +153,15 @@ class Renderer(object):
The footer of the slide.
"""
log.debug(u'format_slide - Start')
# print words
verses = []
words = words.replace(u'\r\n', u'\n')
verses_text = words.split(u'\n')
#print verses_text
text = []
for verse in verses_text:
lines = verse.split(u'\n')
for line in lines:
text.append(line)
split_text = self.pre_render_text(text)
# print split_text
log.debug(u'format_slide - End')
return split_text
@ -173,33 +170,27 @@ class Renderer(object):
#take the width work out approx how many characters and add 50%
line_width = self._rect.width() - self._right_margin
#number of lines on a page - adjust for rounding up.
# print "Metrics ", line_width
page_length = int(self._rect.height() / metrics.height() - 2 ) - 1
ave_line_width = line_width / metrics.averageCharWidth()
ave_line_width = int(ave_line_width + (ave_line_width * 1))
# print "B", ave_line_width
split_pages = []
page = []
split_lines = []
count = 0
for line in text:
#print "C", line, len(line)
#Must be a blank line so keep it.
if len(line) == 0:
line = u' '
while len(line) > 0:
# print "C1", line, len(line)
if len(line) > ave_line_width:
pos = line.find(u' ', ave_line_width)
split_text = line[:pos]
else:
pos = len(line)
split_text = line
# print "E", metrics.width(split_text, -1), line_width
while metrics.width(split_text, -1) > line_width:
#Find the next space to the left
pos = line[:pos].rfind(u' ')
# print "F", pos, line[:pos]
#no more spaces found
if pos == 0:
split_text = line
@ -208,16 +199,9 @@ class Renderer(object):
pos = len(split_text)
else:
split_text = line[:pos]
# print "F1", split_text, line, pos
split_lines.append(split_text)
line = line[pos:]
#Text fits in a line now
# if len(line) <= line_width:
# split_lines.append(line)
# line = u''
# print "G", split_lines
# print "H", line
#print "I", split_lines, page_length
for line in split_lines:
page.append(line)
if len(page) == page_length:
@ -252,7 +236,6 @@ class Renderer(object):
Defaults to *None*. The footer to render.
"""
log.debug(u'generate_frame_from_lines - Start')
#print "Render Lines ", lines
bbox = self._render_lines_unaligned(lines, False)
if footer_lines is not None:
bbox1 = self._render_lines_unaligned(footer_lines, True)
@ -321,8 +304,6 @@ class Renderer(object):
if self.bg_image is not None:
painter.drawImage(0, 0, self.bg_image)
painter.end()
# self.bg_frame_small = self.bg_frame.scaled(QtCore.QSize(280, 210),
# QtCore.Qt.KeepAspectRatio, QtCore.Qt.SmoothTransformation)
log.debug(u'render background End')
def _correctAlignment(self, rect, bbox):

View File

@ -194,9 +194,7 @@ class RenderManager(object):
The words to go on the slides.
"""
log.debug(u'format slide')
#self.calculate_default(self.screen_list[self.current_display][u'size'])
self.build_text_rectangle(self.themedata)
#self.renderer.set_frame_dest(self.width, self.height)
return self.renderer.format_slide(words, False)
def generate_slide(self, main_text, footer_text):
@ -234,7 +232,7 @@ class RenderManager(object):
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.transparent)
newImage.fill(QtCore.Qt.black)
painter = QtGui.QPainter(newImage)
painter.drawImage((w-realw) / 2, (h-realh) / 2, preview)
return newImage
@ -254,6 +252,7 @@ class RenderManager(object):
else:
self.width = screen.width()
self.height = screen.height()
log.debug(u'calculate default %d, %d', self.width, self.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)

View File

@ -93,19 +93,15 @@ class ServiceItem(object):
self.RenderManager.set_override_theme(None)
else:
self.RenderManager.set_override_theme(self.theme)
firstTime = True
for slide in self.service_frames:
formated = self.RenderManager.format_slide(slide[u'raw_slide'])
for format in formated:
frame = None
if firstTime:
frame = self.RenderManager.generate_slide(format,
self.raw_footer)
firstTime = False
lines = u''
for line in format:
lines += line + u'\n'
self.frames.append({u'title': slide[u'title'],u'text':lines,
title = lines.split(u'\n')[0]
self.frames.append({u'title': title ,u'text':lines,
u'image': frame})
elif self.service_item_type == ServiceType.Command:
self.frames = self.service_frames
@ -174,12 +170,12 @@ class ServiceItem(object):
self.service_item_path = path
self.service_frames.append({u'title': frame_title, u'command': None})
def get_oos_repr(self):
def get_service_repr(self):
"""
This method returns some text which can be saved into the OOS
This method returns some text which can be saved into the service
file to represent this item.
"""
oos_header = {
service_header = {
u'name': self.name.lower(),
u'plugin': self.shortname,
u'theme':self.theme,
@ -189,19 +185,19 @@ class ServiceItem(object):
u'type':self.service_item_type,
u'audit':self.audit
}
oos_data = []
service_data = []
if self.service_item_type == ServiceType.Text:
for slide in self.service_frames:
oos_data.append(slide)
service_data.append(slide)
elif self.service_item_type == ServiceType.Image:
for slide in self.service_frames:
oos_data.append(slide[u'title'])
service_data.append(slide[u'title'])
elif self.service_item_type == ServiceType.Command:
for slide in self.service_frames:
oos_data.append(slide[u'title'])
return {u'header': oos_header, u'data': oos_data}
service_data.append(slide[u'title'])
return {u'header': service_header, u'data': service_data}
def set_from_oos(self, serviceitem, path=None):
def set_from_service(self, serviceitem, path=None):
"""
This method takes a service item from a saved service file (passed
from the ServiceManager) and extracts the data actually required.

View File

@ -62,17 +62,17 @@ class SettingsManager(object):
self.showPreviewPanel = str_to_bool(ConfigHelper.get_config(
u'user interface', u'display previewpanel', True))
def toggleMediaManager(self, isVisible):
ConfigHelper.set_config(u'user interface', u'display mediamanager',
isVisible)
def toggleServiceManager(self, isVisible):
ConfigHelper.set_config(u'user interface', u'display servicemanager',
isVisible)
def toggleThemeManager(self, isVisible):
ConfigHelper.set_config(u'user interface', u'display thememanager',
isVisible)
def setUIItemVisibility(self, item=u'', isVisible=True):
if item != u'':
if item == u'ThemeManagerDock':
ConfigHelper.set_config('user interface',
u'display thememanager', isVisible)
elif item == u'ServiceManagerDock':
ConfigHelper.set_config('user interface',
u'display servicemanager', isVisible)
elif item == u'MediaManagerDock':
ConfigHelper.set_config('user interface',
u'display mediamanager', isVisible)
def togglePreviewPanel(self, isVisible):
ConfigHelper.set_config(u'user interface', u'display previewpanel',

View File

@ -131,7 +131,7 @@ class SongXMLParser(object):
try:
self.song_xml = ElementTree(element=XML(xml))
except:
log.debug(u'Invalid xml %s', xml)
log.exception(u'Invalid xml %s', xml)
def get_verses(self):
"""

View File

@ -31,20 +31,11 @@ from openlp.core.ui import AboutForm, SettingsForm, AlertForm, \
ServiceManager, ThemeManager, MainDisplay, SlideController, \
PluginForm
from openlp.core.lib import translate, Plugin, MediaManagerItem, \
SettingsTab, RenderManager, PluginConfig, str_to_bool, \
SettingsTab, RenderManager, PluginConfig, str_to_bool, OpenLPDockWidget, \
SettingsManager, PluginManager, Receiver
from openlp.core.utils import ConfigHelper
class mediaDock(QtGui.QDockWidget):
def __init__(self, parent=None, name=None):
QtGui.QDockWidget.__init__(self, parent)
self.parent = parent
def resizeEvent(self, resizeEvent):
if resizeEvent.size().width() != resizeEvent.oldSize().width():
self.parent.settingsmanager.setDockbarLeft(resizeEvent.size().width())
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
"""
@ -116,7 +107,7 @@ class Ui_MainWindow(object):
self.DefaultThemeLabel.setObjectName(u'DefaultThemeLabel')
self.StatusBar.addPermanentWidget(self.DefaultThemeLabel)
# Create the MediaManager
self.MediaManagerDock = mediaDock(MainWindow)
self.MediaManagerDock = OpenLPDockWidget(MainWindow)
icon = QtGui.QIcon()
icon.addPixmap(QtGui.QPixmap(u':/system/system_mediamanager.png'),
QtGui.QIcon.Normal, QtGui.QIcon.Off)
@ -146,7 +137,7 @@ class Ui_MainWindow(object):
QtCore.Qt.DockWidgetArea(1), self.MediaManagerDock)
self.MediaManagerDock.setVisible(self.settingsmanager.showMediaManager)
# Create the service manager
self.ServiceManagerDock = QtGui.QDockWidget(MainWindow)
self.ServiceManagerDock = OpenLPDockWidget(MainWindow)
ServiceManagerIcon = QtGui.QIcon()
ServiceManagerIcon.addPixmap(
QtGui.QPixmap(u':/system/system_servicemanager.png'),
@ -164,7 +155,7 @@ class Ui_MainWindow(object):
self.ServiceManagerDock.setVisible(
self.settingsmanager.showServiceManager)
# Create the theme manager
self.ThemeManagerDock = QtGui.QDockWidget(MainWindow)
self.ThemeManagerDock = OpenLPDockWidget(MainWindow)
ThemeManagerIcon = QtGui.QIcon()
ThemeManagerIcon.addPixmap(
QtGui.QPixmap(u':/system/system_thememanager.png'),
@ -462,7 +453,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
QtGui.QMainWindow.__init__(self)
self.closeEvent = self.onCloseEvent
self.screenList = screens
self.oosNotSaved = False
self.serviceNotSaved = False
self.settingsmanager = SettingsManager(screens)
self.mainDisplay = MainDisplay(self, screens)
self.generalConfig = PluginConfig(u'General')
@ -519,6 +510,18 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
QtCore.SIGNAL(u'triggered()'), self.onOptionsSettingsItemClicked)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'update_global_theme'), self.defaultThemeChanged)
QtCore.QObject.connect(self.FileNewItem,
QtCore.SIGNAL(u'triggered()'),
self.ServiceManagerContents.onNewService)
QtCore.QObject.connect(self.FileOpenItem,
QtCore.SIGNAL(u'triggered()'),
self.ServiceManagerContents.onLoadService)
QtCore.QObject.connect(self.FileSaveItem,
QtCore.SIGNAL(u'triggered()'),
self.ServiceManagerContents.onQuickSaveService)
QtCore.QObject.connect(self.FileSaveAsItem,
QtCore.SIGNAL(u'triggered()'),
self.ServiceManagerContents.onSaveService)
#warning cyclic dependency
#RenderManager needs to call ThemeManager and
#ThemeManager needs to call RenderManager
@ -532,8 +535,8 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
self.plugin_helpers[u'service'] = self.ServiceManagerContents
self.plugin_helpers[u'settings'] = self.settingsForm
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
# hook methods have to happen after find_plugins. Find plugins needs
# the controllers hence the hooks have moved from setupUI() to here
# Find and insert settings tabs
log.info(u'hook settings')
self.plugin_manager.hook_settings_tabs(self.settingsForm)
@ -614,10 +617,10 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
"""
Hook to close the main window and display windows on exit
"""
if self.oosNotSaved == True:
if self.serviceNotSaved == True:
ret = QtGui.QMessageBox.question(None,
translate(u'mainWindow', u'Save Changes to Service?'),
translate(u'mainWindow', u'Your service has been changed, do you want to save those changes?'),
translate(u'mainWindow', u'Your service has changed, do you want to save those changes?'),
QtGui.QMessageBox.StandardButtons(
QtGui.QMessageBox.Cancel |
QtGui.QMessageBox.Discard |
@ -640,45 +643,57 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
event.accept()
def cleanUp(self):
"""
Runs all the cleanup code before OpenLP shuts down
"""
# Clean temporary files used by services
self.ServiceManagerContents.cleanUp()
# Call the cleanup method to shutdown plugins.
log.info(u'cleanup plugins')
self.plugin_manager.finalise_plugins()
def OosChanged(self, reset=False, oosName=None):
def serviceChanged(self, reset=False, serviceName=None):
"""
Hook to change the title if the OOS has been changed
reset - tells if the OOS has been cleared or saved
oosName - is the name of the OOS (if it has one)
Hook to change the main window title when the service changes
``reset``
Shows if the service has been cleared or saved
``serviceName``
The name of the service (if it has one)
"""
if not oosName:
if not serviceName:
service_name = u'(unsaved service)'
else:
service_name = oosName
service_name = serviceName
if reset == True:
self.oosNotSaved = False
self.serviceNotSaved = False
title = u'%s - %s' % (self.mainTitle, service_name)
else:
self.oosNotSaved = True
self.serviceNotSaved = True
title = u'%s - %s*' % (self.mainTitle, service_name)
self.setWindowTitle(title)
def defaultThemeChanged(self, theme):
self.DefaultThemeLabel.setText(self.defaultThemeText + theme)
def toggleMediaManager(self):
mediaBool = self.MediaManagerDock.isVisible()
self.MediaManagerDock.setVisible(not mediaBool)
self.settingsmanager.toggleMediaManager(not mediaBool)
def toggleMediaManager(self, visible):
if self.MediaManagerDock.isVisible() != visible:
self.MediaManagerDock.setVisible(visible)
self.settingsmanager.setUIItemVisibility(
self.MediaManagerDock.objectName(), visible)
def toggleServiceManager(self):
serviceBool = self.ServiceManagerDock.isVisible()
self.ServiceManagerDock.setVisible(not serviceBool)
self.settingsmanager.toggleServiceManager(not serviceBool)
def toggleServiceManager(self, visible):
if self.ServiceManagerDock.isVisible() != visible:
self.ServiceManagerDock.setVisible(visible)
self.settingsmanager.setUIItemVisibility(
self.ServiceManagerDock.objectName(), visible)
def toggleThemeManager(self):
themeBool = self.ThemeManagerDock.isVisible()
self.ThemeManagerDock.setVisible(not themeBool)
self.settingsmanager.toggleThemeManager(not themeBool)
def toggleThemeManager(self, visible):
if self.ThemeManagerDock.isVisible() != visible:
self.ThemeManagerDock.setVisible(visible)
self.settingsmanager.setUIItemVisibility(
self.ThemeManagerDock.objectName(), visible)
def togglePreviewPanel(self):
previewBool = self.PreviewController.Panel.isVisible()

View File

@ -24,6 +24,7 @@
import os
import sys
import string
import logging
import cPickle
import zipfile
@ -83,10 +84,9 @@ class Iter(QtGui.QTreeWidgetItemIterator):
class ServiceManager(QtGui.QWidget):
"""
Manages the orders of service. Currently this involves taking
text strings from plugins and adding them to an OOS file. In
future, it will also handle zipping up all the resources used into
one lump.
Manages the services. This involves taking text strings from plugins and
adding them to the service. This service can then be zipped up with all
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
@ -100,6 +100,7 @@ class ServiceManager(QtGui.QWidget):
self.parent = parent
self.serviceItems = []
self.serviceName = u''
self.isNew = True
self.Layout = QtGui.QVBoxLayout(self)
self.Layout.setSpacing(0)
self.Layout.setMargin(0)
@ -272,7 +273,7 @@ class ServiceManager(QtGui.QWidget):
self.serviceItems.remove(self.serviceItems[item])
self.serviceItems.insert(0, temp)
self.repaintServiceList(0, count)
self.parent.OosChanged(False, self.serviceName)
self.parent.serviceChanged(False, self.serviceName)
def onServiceUp(self):
"""
@ -285,7 +286,7 @@ class ServiceManager(QtGui.QWidget):
self.serviceItems.remove(self.serviceItems[item])
self.serviceItems.insert(item - 1, temp)
self.repaintServiceList(item - 1, count)
self.parent.OosChanged(False, self.serviceName)
self.parent.serviceChanged(False, self.serviceName)
def onServiceDown(self):
"""
@ -298,7 +299,7 @@ class ServiceManager(QtGui.QWidget):
self.serviceItems.remove(self.serviceItems[item])
self.serviceItems.insert(item + 1, temp)
self.repaintServiceList(item + 1, count)
self.parent.OosChanged(False, self.serviceName)
self.parent.serviceChanged(False, self.serviceName)
def onServiceEnd(self):
"""
@ -310,7 +311,7 @@ class ServiceManager(QtGui.QWidget):
self.serviceItems.remove(self.serviceItems[item])
self.serviceItems.insert(len(self.serviceItems), temp)
self.repaintServiceList(len(self.serviceItems) - 1, count)
self.parent.OosChanged(False, self.serviceName)
self.parent.serviceChanged(False, self.serviceName)
def onNewService(self):
"""
@ -319,7 +320,8 @@ class ServiceManager(QtGui.QWidget):
self.ServiceManagerList.clear()
self.serviceItems = []
self.serviceName = u''
self.parent.OosChanged(True, self.serviceName)
self.isNew = True
self.parent.serviceChanged(True, self.serviceName)
def onDeleteFromService(self):
"""
@ -329,9 +331,9 @@ class ServiceManager(QtGui.QWidget):
if item is not -1:
self.serviceItems.remove(self.serviceItems[item])
self.repaintServiceList(0, 0)
self.parent.OosChanged(False, self.serviceName)
self.parent.serviceChanged(False, self.serviceName)
def repaintServiceList(self, serviceItem, serviceItemCount):
def repaintServiceList(self, serviceItem, serviceItemCount):
"""
Clear the existing service list and prepaint all the items
Used when moving items as the move takes place in supporting array,
@ -361,23 +363,31 @@ class ServiceManager(QtGui.QWidget):
if serviceItem == itemcount and serviceItemCount == count:
self.ServiceManagerList.setCurrentItem(treewidgetitem1)
def onSaveService(self):
def onSaveService(self, quick=False):
"""
Save the current service in a zip file
Save the current service in a zip (OSZ) file
This file contains
* An ood which is a pickle of the service items
* An osd which is a pickle of the service items
* All image, presentation and video files needed to run the service.
"""
filename = QtGui.QFileDialog.getSaveFileName(self,
u'Save Order of Service',self.config.get_last_dir() )
filename = unicode(filename)
if not quick or self.isNew:
filename = QtGui.QFileDialog.getSaveFileName(self,
u'Save Service', self.config.get_last_dir())
else:
filename = self.config.get_last_dir()
if filename != u'':
splittedFile = filename.split(u'.')
if splittedFile[-1] != u'osz':
filename = filename + u'.osz'
filename = unicode(filename)
self.isNew = False
self.config.set_last_dir(filename)
service = []
servicefile= filename + u'.ood'
zip = zipfile.ZipFile(unicode(filename) + u'.oos', 'w')
servicefile = filename + u'.osd'
zip = zipfile.ZipFile(unicode(filename), 'w')
for item in self.serviceItems:
service.append({u'serviceitem':item[u'data'].get_oos_repr()})
service.append(
{u'serviceitem':item[u'data'].get_service_repr()})
if item[u'data'].service_item_type == ServiceType.Image or \
item[u'data'].service_item_type == ServiceType.Command:
for frame in item[u'data'].frames:
@ -393,17 +403,21 @@ class ServiceManager(QtGui.QWidget):
os.remove(servicefile)
except:
pass #if not present do not worry
self.parent.OosChanged(True, filename + u'.oos')
name = filename.split(os.path.sep)
self.serviceName = name[-1]
self.parent.serviceChanged(True, self.serviceName)
def onQuickSaveService(self):
self.onSaveService(True)
def onLoadService(self):
"""
Load an existing service from disk and rebuilds the serviceitems
All files retrieved from the zip file are placed in a temporary
directory and will only be used for this service.
Load an existing service from disk and rebuild the serviceitems. All
files retrieved from the zip file are placed in a temporary directory
and will only be used for this service.
"""
filename = QtGui.QFileDialog.getOpenFileName(self,
u'Open Order of Service',self.config.get_last_dir(),
u'Services (*.oos)')
filename = QtGui.QFileDialog.getOpenFileName(self, u'Open Service',
self.config.get_last_dir(), u'Services (*.osz)')
filename = unicode(filename)
name = filename.split(os.path.sep)
if filename != u'':
@ -413,14 +427,18 @@ class ServiceManager(QtGui.QWidget):
filexml = None
themename = None
for file in zip.namelist():
names = file.split(os.path.sep)
if os.name == u'nt':
winfile = string.replace(file, '/', os.path.sep)
names = winfile.split(os.path.sep)
else:
names = file.split(os.path.sep)
file_to = os.path.join(self.servicePath,
names[len(names) - 1])
file_data = zip.read(file)
f = open(file_to, u'w')
f.write(file_data)
f = open(file_to, u'wb')
f.write(zip.read(file))
f.flush()
f.close()
if file_to.endswith(u'ood'):
if file_to.endswith(u'osd'):
p_file = file_to
f = open(p_file, u'r')
items = cPickle.load(f)
@ -429,18 +447,30 @@ class ServiceManager(QtGui.QWidget):
for item in items:
serviceitem = ServiceItem()
serviceitem.RenderManager = self.parent.RenderManager
serviceitem.set_from_oos(item, self.servicePath )
serviceitem.set_from_service(item, self.servicePath )
self.addServiceItem(serviceitem)
try:
os.remove(p_file)
if os.path.isfile(p_file):
os.remove(p_file)
except:
#if not present do not worry
pass
log.exception(u'Failed to remove osd file')
except:
log.error(u'Problem processing oos load %s', sys.exc_info()[0])
pass
log.exception(u'Problem loading a service file')
self.isNew = False
self.serviceName = name[len(name) - 1]
self.parent.OosChanged(True, self.serviceName)
self.parent.serviceChanged(True, self.serviceName)
def cleanUp(self):
"""
Empties the servicePath of temporary files
"""
for file in os.listdir(self.servicePath):
file_path = os.path.join(self.servicePath, file)
try:
if os.path.isfile(file_path):
os.remove(file_path)
except:
log.exception(u'Failed to clean up servicePath')
def onThemeComboBoxSelected(self, currentIndex):
"""
@ -483,7 +513,7 @@ class ServiceManager(QtGui.QWidget):
treewidgetitem1.setData(0, QtCore.Qt.UserRole,
QtCore.QVariant(count))
count = count + 1
self.parent.OosChanged(False, self.serviceName)
self.parent.serviceChanged(False, self.serviceName)
def makePreview(self):
"""

View File

@ -27,7 +27,6 @@ import logging
from PyQt4 import QtCore, QtGui
from openlp.core.lib import SettingsTab
from openlp.core.resources import *
from openlp.core.ui import GeneralTab, ThemesTab, AlertsTab
from settingsdialog import Ui_SettingsDialog

View File

@ -157,13 +157,6 @@ class SlideController(QtGui.QWidget):
self.DelaySpinBox.setSuffix(translate(u'SlideController', u's'))
self.ControllerLayout.addWidget(self.Toolbar)
#sizeToolbarPolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed,
# QtGui.QSizePolicy.Fixed)
#sizeToolbarPolicy.setHorizontalStretch(0)
#sizeToolbarPolicy.setVerticalStretch(0)
#sizeToolbarPolicy.setHeightForWidth(
# self.Toolbar.sizePolicy().hasHeightForWidth())
#self.Toolbar.setSizePolicy(sizeToolbarPolicy)
# Screen preview area
self.PreviewFrame = QtGui.QFrame(self.Splitter)
self.PreviewFrame.setGeometry(QtCore.QRect(0, 0, 300, 225))
@ -284,29 +277,26 @@ class SlideController(QtGui.QWidget):
log.debug(u'displayServiceManagerItems Start')
before = time.time()
self.serviceitem = serviceitem
slide_image = self.serviceitem.frames[0][u'image']
size = slide_image.size()
slide_width = self.settingsmanager.slidecontroller_image
slide_height = slide_width * size.height() / size.width()
self.PreviewListWidget.clear()
self.PreviewListWidget.setRowCount(0)
self.PreviewListWidget.setColumnWidth(0, slide_width)
self.PreviewListWidget.setColumnWidth(0, self.settingsmanager.slidecontroller_image)
for framenumber, frame in enumerate(self.serviceitem.frames):
self.PreviewListWidget.setRowCount(self.PreviewListWidget.rowCount() + 1)
item = QtGui.QTableWidgetItem()
label = QtGui.QLabel()
label.setMargin(8)
#It is a Image
if frame[u'text'] == None:
pixmap = self.parent.RenderManager.resize_image(frame[u'image'], slide_width, slide_height)
pixmap = self.parent.RenderManager.resize_image(frame[u'image'])
label.setScaledContents(True)
label.setPixmap(QtGui.QPixmap.fromImage(pixmap))
else:
label.setText(frame[u'text'])
self.PreviewListWidget.setCellWidget(framenumber, 0, label)
self.PreviewListWidget.setItem(framenumber, 0, item)
slide_height = self.settingsmanager.slidecontroller_image * self.parent.RenderManager.screen_ratio
self.PreviewListWidget.setRowHeight(framenumber, slide_height)
slide_width = self.PreviewListWidget.viewport().size().width()
self.PreviewListWidget.setColumnWidth(0, slide_width)
self.PreviewListWidget.setColumnWidth(0, self.PreviewListWidget.viewport().size().width())
if slideno > self.PreviewListWidget.rowCount():
self.PreviewListWidget.selectRow(self.PreviewListWidget.rowCount())
else:
@ -314,7 +304,8 @@ class SlideController(QtGui.QWidget):
self.onSlideSelected()
self.PreviewListWidget.setFocus()
log.info(u'Display Rendering took %4s' % (time.time() - before))
Receiver().send_message(u'audit_live', self.serviceitem.audit)
if self.serviceitem.audit != u'':
Receiver().send_message(u'audit_live', self.serviceitem.audit)
log.debug(u'displayServiceManagerItems End')
#Screen event methods

View File

@ -19,15 +19,17 @@ Place, Suite 330, Boston, MA 02111-1307 USA
import time
import sys
import os, os.path
import logging
from PyQt4 import QtGui, QtCore
from PyQt4.QtCore import *
from PyQt4.QtGui import *
mypath=os.path.split(os.path.abspath(__file__))[0]
sys.path.insert(0,(os.path.join(mypath, '..','..', '..','..')))
mypath = os.path.split(os.path.abspath(__file__))[0]
sys.path.insert(0, (os.path.join(mypath, '..', '..', '..', '..')))
from openlp.core.ui import ServiceManager
from openlp.plugins.images.lib import ImageServiceItem
import logging
logging.basicConfig(filename='test_service_manager.log', level=logging.INFO,
filemode='w')
@ -36,69 +38,72 @@ logging.basicConfig(filename='test_service_manager.log', level=logging.INFO,
# return sys._getframe(depth).f_code.co_name
global app
global log
log=logging.getLogger(u'TestServiceManager')
log = logging.getLogger(u'TestServiceManager')
class TestServiceManager_base:
def __init__(self):
pass
def setup_class(self):
log.info( "class setup"+unicode(self))
log.info( "class setup" + unicode(self))
try:
if app is None:
app = QtGui.QApplication([])
except UnboundLocalError:
app = QtGui.QApplication([])
def teardown_class(self):
pass
def setup_method(self, method):
log.info(u'Setup method:' + unicode(method))
self.expected_answer="Don't know yet"
self.answer=None
self.s=ServiceManager(None)
self.expected_answer = "Don't know yet"
self.answer = None
self.s = ServiceManager(None)
log.info(u'--------------- Setup Done -------------')
def teardown_method(self, method):
self.s=None
self.s = None
def select_row(self, row):
# now select the line we just added
# first get the index
i=QModelIndex(self.s.service_data.index(0,0))
i = QModelIndex(self.s.service_data.index(0,0))
# make a selection of it
self.sm=QItemSelectionModel(self.s.service_data)
self.sm = QItemSelectionModel(self.s.service_data)
self.sm.select(i, QItemSelectionModel.ClearAndSelect)
log.info(unicode(self.sm.selectedIndexes()))
self.s.TreeView.setSelectionModel(self.sm)
log.info(u'Selected indexes = ' + unicode(self.s.TreeView.selectedIndexes()))
log.info(u'Selected indexes = ' + unicode(
self.s.TreeView.selectedIndexes()))
def test_easy(self):
log.info(u'test_easy')
item=ImageServiceItem(None)
item = ImageServiceItem(None)
item.add(u'test.gif')
self.s.addServiceItem(item)
answer = self.s.oos_as_text()
answer = self.s.service_as_text()
log.info(u'Answer = ' + unicode(answer))
lines=answer.split(u'\n')
lines = answer.split(u'\n')
log.info(u'lines = ' + unicode(lines))
assert lines[0].startswith(u'# <openlp.plugins.images.imageserviceitem.ImageServiceItem object')
assert lines[1] == "test.gif"
log.info(u'done')
def test_2items_as_separate_items(self):
# If nothing is selected when item is added, a new base service item is added
# If nothing is selected when item is added, a new base service item
# is added
log.info(u'test_2items_as_separate_items')
item=ImageServiceItem(None)
item = ImageServiceItem(None)
item.add(u'test.gif')
self.s.addServiceItem(item)
item=ImageServiceItem(None)
item = ImageServiceItem(None)
item.add(u'test2.gif')
item.add(u'test3.gif')
self.s.addServiceItem(item)
answer = self.s.oos_as_text()
answer = self.s.service_as_text()
log.info(u'Answer = ' + unicode(answer))
lines=answer.split(u'\n')
lines = answer.split(u'\n')
log.info(u'lines = ' + unicode(lines))
assert lines[0].startswith(u'# <openlp.plugins.images.imageserviceitem.ImageServiceItem object')
assert lines[1] == "test.gif"
@ -108,20 +113,22 @@ class TestServiceManager_base:
log.info(u'done')
def test_2items_merged(self):
# If the first object is selected when item is added it should be extended
# If the first object is selected when item is added it should be
# extended
log.info(u'test_2items_merged')
item=ImageServiceItem(None)
item = ImageServiceItem(None)
item.add(u'test.gif')
self.s.addServiceItem(item)
self.select_row(0)
log.info(u'Selected indexes = ' + unicode(self.s.TreeView.selectedIndexes()))
item=ImageServiceItem(None)
log.info(u'Selected indexes = ' + unicode(
self.s.TreeView.selectedIndexes()))
item = ImageServiceItem(None)
item.add(u'test2.gif')
item.add(u'test3.gif')
self.s.addServiceItem(item)
answer = self.s.oos_as_text()
answer = self.s.service_as_text()
log.info(u'Answer = ' + unicode(answer))
lines=answer.split(u'\n')
lines = answer.split(u'\n')
log.info(u'lines = ' + unicode(lines))
assert lines[0].startswith(u'# <openlp.plugins.images.imageserviceitem.ImageServiceItem object')
assert lines[1] == "test.gif"
@ -138,7 +145,6 @@ class TestServiceManager_base:
if __name__ == "__main__":
t=TestServiceManager_base()
t.setup_class()
t.setup_method(None)

View File

@ -27,7 +27,7 @@ import logging
from PyQt4 import QtCore, QtGui
from datetime import date
from openlp.core.lib import Plugin, Receiver, translate
from openlp.core.lib import Plugin, Receiver, translate, str_to_bool
from openlp.plugins.audit.lib import AuditTab
class AuditPlugin(Plugin):
@ -95,17 +95,49 @@ class AuditPlugin(Plugin):
log.info(u'Plugin Initialising')
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'audit_live'), self.onReceiveAudit)
self.auditFile = open(u'openlp.aud', 'a')
self.auditActive = False
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'audit_changed'), self.onUpdateAudit)
self.auditFileName = self.config.get_config(u'audit file', u'')
self.auditActive = str_to_bool(self.config.get_config(u'audit active', False))
if self.auditFileName == u'':
self.auditActive = False
self.ToolsAuditItem.setEnabled(False)
self.auditFile = None
else:
self.auditFile = open(self.auditFileName, u'a')
self.ToolsAuditItem.setChecked(self.auditActive)
def toggleAuditState(self):
self.auditActive = not self.auditActive
self.config.set_config(u'audit active', self.auditActive)
def onReceiveAudit(self, auditData):
"""
Audit a live song from SlideController
"""
if self.auditActive:
self.auditFile.write(u'%s,%s\n' % (date.today(), auditData))
for author in auditData[1]:
self.auditFile.write(u'\"%s\",\"%s\",\"%s\",\"%s\"\n' % (date.today(), auditData[0], author, auditData[2]))
self.auditFile.flush()
def onUpdateAudit(self):
"""
Someone may have changed to audit details
Sort out the file and the auditing state
"""
self.auditFileNameNew = self.config.get_config(u'audit file', u'')
self.auditActive = str_to_bool(self.config.get_config(u'audit active', False))
if self.auditFileNameNew == u'':
self.auditActive = False
self.ToolsAuditItem.setChecked(self.auditActive)
self.ToolsAuditItem.setEnabled(False)
return
self.ToolsAuditItem.setEnabled(True)
if self.auditFileNameNew != self.auditFileName:
if self.auditFile is not None:
self.auditFile.close()
self.auditFile = open(self.auditFileNameNew, u'a')
def finalise(self):
log.debug(u'Finalise')
if self.auditFile is not None:

View File

@ -35,25 +35,30 @@ class AuditTab(SettingsTab):
def setupUi(self):
self.setObjectName(u'AuditTab')
self.AuditLayout = QtGui.QFormLayout(self)
self.AuditLayout.setObjectName(u'AuditLayout')
self.AuditModeGroupBox = QtGui.QGroupBox(self)
self.AuditModeGroupBox.setObjectName(u'AuditModeGroupBox')
self.AuditModeLayout = QtGui.QVBoxLayout(self.AuditModeGroupBox)
self.AuditModeLayout.setSpacing(8)
self.AuditModeLayout.setMargin(8)
self.AuditModeLayout.setObjectName(u'AuditModeLayout')
self.AuditPortSpinBox = QtGui.QSpinBox(self.AuditModeGroupBox)
self.AuditPortSpinBox.setObjectName(u'AuditPortSpinBox')
self.AuditPortSpinBox.setMaximum(32767)
self.AuditModeLayout.addWidget(self.AuditPortSpinBox)
self.AuditActive = QtGui.QCheckBox(self.AuditModeGroupBox)
self.AuditActive.setObjectName(u'AuditPortSpinBox')
self.AuditModeLayout.addWidget(self.AuditActive)
self.WarningLabel = QtGui.QLabel(self.AuditModeGroupBox)
self.WarningLabel.setObjectName(u'WarningLabel')
self.AuditModeLayout.addWidget(self.WarningLabel)
self.AuditLayout.setWidget(0, QtGui.QFormLayout.LabelRole, self.AuditModeGroupBox)
self.verticalLayout = QtGui.QVBoxLayout(self.AuditModeGroupBox)
self.verticalLayout.setObjectName("verticalLayout")
self.horizontalLayout = QtGui.QHBoxLayout()
self.horizontalLayout.setObjectName("horizontalLayout")
self.AuditFileName = QtGui.QLineEdit(self)
self.AuditFileName.setObjectName("AuditFileName")
self.horizontalLayout.addWidget(self.AuditFileName)
icon1 = QtGui.QIcon()
icon1.addPixmap(QtGui.QPixmap(u':/imports/import_load.png'), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.AuditFileButton = QtGui.QPushButton(self)
self.AuditFileButton.setObjectName("AuditFileButton")
self.AuditFileButton.setIcon(icon1)
self.horizontalLayout.addWidget(self.AuditFileButton)
self.verticalLayout.addLayout(self.horizontalLayout)
self.AuditActive = QtGui.QCheckBox(self)
self.AuditActive.setObjectName("AuditActive")
self.verticalLayout.addWidget(self.AuditActive)
self.WarningLabel = QtGui.QLabel(self)
self.WarningLabel.setObjectName("WarningLabel")
self.verticalLayout.addWidget(self.WarningLabel)
QtCore.QObject.connect(self.AuditFileButton,
QtCore.SIGNAL(u'pressed()'), self.onAuditFileButtonClicked)
def retranslateUi(self):
self.AuditModeGroupBox.setTitle(translate(u'AuditTab', u'Audit File'))
@ -61,10 +66,16 @@ class AuditTab(SettingsTab):
self.WarningLabel.setText(translate(u'AuditTab', u'A restart is needed for this change to become effective'))
def load(self):
self.AuditPortSpinBox.setValue(int(self.config.get_config(u'Audit port', 4316)))
self.AuditFileName.setText(self.config.get_config(u'Audit file', u''))
self.AuditActive.setChecked(int(self.config.get_config(u'startup', 0)))
def save(self):
self.config.set_config(u'Audit port', unicode(self.AuditPortSpinBox.value()))
self.config.set_config(u'startup', unicode(self.AuditActive.checkState()))
def onAuditFileButtonClicked(self):
filename = QtGui.QFileDialog.getOpenFileName(self, u'Audit File',self.AuditFileName.text())
if filename != u'':
filename = unicode(filename)
self.AuditFileName.setText(filename)
def save(self):
self.config.set_config(u'Audit file', unicode(self.AuditFileName.text()))
self.config.set_config(u'startup', unicode(self.AuditActive.checkState()))
Receiver().send_message(u'audit_changed')

View File

@ -192,7 +192,8 @@ class BibleManager(object):
nbible.save_meta(u'proxypass', proxypass)
return True
else:
log.debug(u'register_http_file_bible %s not created already exists', biblename)
log.debug(u'register_http_file_bible %s not created already exists',
biblename)
return False
def register_csv_file_bible(self, biblename, booksfile, versefile):
@ -201,34 +202,46 @@ class BibleManager(object):
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)
log.debug(u'register_CSV_file_bible %s,%s,%s',
biblename, booksfile, versefile)
if self._is_new_bible(biblename):
nbible = BibleDBImpl(self.biblePath, biblename, self.config) # Create new Bible
nbible.create_tables() # Create Database
self.bible_db_cache[biblename] = nbible # cache the database for use later
bcsv = BibleCSVImpl(nbible) # create the loader and pass in the database
# 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)
bcsv.load_data(booksfile, versefile, self.dialogobject)
return True
else:
log.debug(u'register_csv_file_bible %s not created already exists', biblename)
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.
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):
nbible = BibleDBImpl(self.biblePath, biblename, self.config) # Create new Bible
nbible.create_tables() # Create Database
self.bible_db_cache[biblename] = nbible # cache the database for use later
bcsv = BibleOSISImpl(self.biblePath, nbible) # create the loader and pass in the database
# 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 = BibleOSISImpl(self.biblePath, nbible)
bcsv.load_data(osisfile, self.dialogobject)
return True
else:
log.debug(u'register_OSIS_file_bible %s , %s not created already exists', biblename, osisfile)
log.debug(
u'register_OSIS_file_bible %s , %s not created already exists',
biblename, osisfile)
return False
def get_bibles(self, mode=BibleMode.Full):
@ -271,7 +284,8 @@ c
book and chapterMaxBibleBookVerses
"""
log.debug(u'get_book_verse_count %s,%s,%s', bible, book, chapter)
return self.bible_db_cache[bible].get_max_bible_book_verses(book, chapter)
return self.bible_db_cache[bible].get_max_bible_book_verses(
book, chapter)
def get_verse_from_text(self, bible, versetext):
"""
@ -285,7 +299,8 @@ c
"""
Saves the bibles meta data
"""
log.debug(u'save_meta data %s,%s, %s,%s', bible, version, copyright, permissions)
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)
@ -297,7 +312,8 @@ c
log.debug(u'get_meta %s,%s', bible, key)
return self.bible_db_cache[bible].get_meta(key)
def get_verse_text(self, bible, bookname, schapter, echapter, sverse, everse=0):
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)
@ -311,8 +327,10 @@ c
text = []
self.media.setQuickMsg1(u'')
self.media.setQuickMsg2(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
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
if self.bible_http_cache[bible] is not None:
book= self.bible_db_cache[bible].get_bible_book(bookname)
if book == None:
@ -320,49 +338,61 @@ c
log.debug(u'get_verse_text : new book')
for chapter in range(schapter, echapter + 1):
self.media.setQuickMsg2(u'%s: %s'% (bookname, chapter))
search_results = self.bible_http_cache [bible].get_bible_chapter(bible, 0, bookname, chapter)
search_results = \
self.bible_http_cache[bible].get_bible_chapter(
bible, 0, 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.
## 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)
book = self.bible_db_cache[bible].get_bible_book(
bookname)
if book == 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())
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)
v = self.bible_db_cache[bible].get_bible_chapter(
book.id, chapter)
if v == None:
self.media.setQuickMsg2(u'%s: %s'%(bookname, chapter))
self.bible_db_cache[bible].create_chapter(book.id, \
chapter, \
search_results.get_verselist())
self.media.setQuickMsg2(u'%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)
v = self.bible_db_cache[bible].get_bible_chapter(
book.id, chapter)
if v == None:
try:
self.media.setQuickMsg1(u'Downloading')
self.media.setQuickMsg2(u'%s: %s'% (bookname, chapter))
search_results = self.bible_http_cache [bible].get_bible_chapter(bible, book.id, bookname, chapter)
self.media.setQuickMsg2(u'%s: %s'% \
(bookname, chapter))
search_results = \
self.bible_http_cache[bible].get_bible_chapter(
bible, book.id, 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.error(u'Errow thrown %s', sys.exc_info()[1])
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)
text = self.bible_db_cache[bible].get_bible_text(bookname,
schapter, sverse, everse)
else:
for i in range (schapter, echapter + 1):
if i == schapter:
@ -375,7 +405,8 @@ c
start = 1
end = self.get_book_verse_count(bible, bookname, i)
txt = self.bible_db_cache[bible].get_bible_text(bookname, i, start, end)
txt = self.bible_db_cache[bible].get_bible_text(
bookname, i, start, end)
text.extend(txt)
return text

View File

@ -9,21 +9,23 @@ To allow easy development of new "things to display". Examples:
* Powerpoint/Openoffice Impress
* Lyrics :) (with chords, rich text, etc...)
* Musical score
* Midi files (hmmm, that's not a thing to display, but feels like it should be there...)
* Midi files (hmmm, that's not a thing to display, but feels like it should be
there...)
* Audio files, CDs (hmmm again)
* Collections of pictures
* Alerts to members of the congregation
... etc.
The scope of these plugins is "things for display purposes", so
each needs to be able to:
The scope of these plugins is "things for display purposes", so each needs to
be able to:
* Render their display (on the projection screen and in a "shrunken form"
for preview purposes)
These plugins need to be part of an OOS. This means they need to
* Be able to tell the OOS manager code what to put in the OOS for their "bit"
These plugins need to be part of a service. This means they need to
* Be able to tell the service manager code what to put in the service for their
"bit"
* Have a "tab" in the media manager, which they can render on request
to allow bits to be added to the OOS (or indeed shown live)
to allow bits to be added to the service (or indeed shown live)
In addition, some plugins need to be able to show
* How their multiple screens of data are split (eg verses)
@ -41,29 +43,29 @@ Other basic things all plugins will need:
* A version number
* Helpfile?
Funnily enough, the core lyrics engine fits those requirements, so
could actually form a plugin...
Funnily enough, the core lyrics engine fits those requirements, so could
actually form a plugin...
Each OOS entry may be made up of multiple plugins (to do text on
video), so each plugin that contributes to an OOS item will need a
"layering" priority.
Each service entry may be made up of multiple plugins (to do text on video), so
each plugin that contributes to a service item will need a "layering"
priority.
Plugin management
-----------------
Plugins will be packages within the plugins/ directory. The plugin
manager will scan this directory when openlp loads for any class which
is based on the base Plugin class (or should we call it the
DisplayPlugin class to allow for other sorts??)
Plugins will be packages within the plugins/ directory. The plugin manager
will scan this directory when openlp loads for any class which is based on the
base Plugin class (or should we call it the DisplayPlugin class to allow for
other sorts??)
These plugins are then queried for their capabilities/requirements and
spaces made in the prefs UI as required, and in the media manager.
The OOS manager can find out what plugins it has available (we need to
report missing plugins when an OOS is loaded).
The service manager can find out what plugins it has available (we need to
report missing plugins when a service is loaded).
The display manager will get a ref to a/some plugin(s) from the OOS
manager when each OOS item is made live, and can then call on each to
The display manager will get a ref to a/some plugin(s) from the service
manager when each service item is made live, and can then call on each to
render their display.
Each plugin will have basic attributes for
@ -78,8 +80,8 @@ Each plugin will have basic attributes for
and a set of API functions for
* media manager rendering and handling
* creating OOS data
* being told OOS data
* creating service data
* being told service data
* set paint context
* render
* selecting a screen to display

View File

@ -23,8 +23,8 @@ Place, Suite 330, Boston, MA 02111-1307 USA
# http://www.oooforum.org/forum/viewtopic.phtml?t=5252
# http://wiki.services.openoffice.org/wiki/Documentation/DevGuide/Working_with_Presentations
# http://mail.python.org/pipermail/python-win32/2008-January/006676.html
#http://www.linuxjournal.com/content/starting-stopping-and-connecting-openoffice-python
#http://nxsy.org/comparing-documents-with-openoffice-and-python
# http://www.linuxjournal.com/content/starting-stopping-and-connecting-openoffice-python
# http://nxsy.org/comparing-documents-with-openoffice-and-python
import logging
import os , subprocess
@ -80,8 +80,9 @@ class ImpressController(object):
"""
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 ts started.
Once the environment is available the presentation is loaded and started.
OpenOffice task started earlier. If OpenOffice is not present is is
started. Once the environment is available the presentation is loaded
and started.
``presentation``
The file name of the presentatios to the run.
@ -98,19 +99,22 @@ class ImpressController(object):
try:
properties = []
properties = tuple(properties)
self.document = desktop.loadComponentFromURL(url, "_blank", 0, properties)
self.document = desktop.loadComponentFromURL(
url, "_blank", 0, properties)
self.presentation = self.document.getPresentation()
self.presentation.start()
self.xSlideShowController = desktop.getCurrentComponent().Presentation.getController()
self.xSlideShowController = \
desktop.getCurrentComponent().Presentation.getController()
except:
log.error(u'Failed reason %s' % sys.exc_info())
log.exception(u'Failed to load presentation')
def getUNODesktop(self):
log.debug(u'getUNODesktop')
ctx = None
loop = 0
context = uno.getComponentContext()
resolver = context.ServiceManager.createInstanceWithContext(u'com.sun.star.bridge.UnoUrlResolver', context)
resolver = context.ServiceManager.createInstanceWithContext(
u'com.sun.star.bridge.UnoUrlResolver', context)
while ctx == None and loop < 3:
try:
ctx = resolver.resolve(u'uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext')
@ -119,10 +123,11 @@ class ImpressController(object):
loop += 1
try:
smgr = ctx.ServiceManager
desktop = smgr.createInstanceWithContext( "com.sun.star.frame.Desktop", ctx )
desktop = smgr.createInstanceWithContext(
"com.sun.star.frame.Desktop", ctx )
return desktop
except:
log.error(u'Failed reason %s' % sys.exc_info())
log.exception(u'Failed to get UNO desktop')
return None
def getCOMDesktop(self):
@ -132,7 +137,7 @@ class ImpressController(object):
desktop = smgr.createInstance( "com.sun.star.frame.Desktop")
return desktop
except:
log.error(u'Failed reason %s' % sys.exc_info())
log.exception(u'Failed to get COM desktop')
return None
def closePresentation(self):

View File

@ -29,8 +29,8 @@ import logging
from PyQt4 import QtCore, QtGui
from openlp.core.lib import Plugin, MediaManagerItem
from openlp.plugins.presentations.lib import PresentationMediaItem, PresentationTab, \
ImpressController
from openlp.plugins.presentations.lib import PresentationMediaItem, \
PresentationTab, ImpressController
try:
from openlp.plugins.presentations.lib import PowerpointController
except:
@ -64,7 +64,8 @@ class PresentationPlugin(Plugin):
"""
Create the Media Manager List
"""
self.media_item = PresentationMediaItem(self, self.icon, u'Presentations', self.controllers)
self.media_item = PresentationMediaItem(
self, self.icon, u'Presentations', self.controllers)
return self.media_item
def registerControllers(self, handle, controller):
@ -77,7 +78,8 @@ class PresentationPlugin(Plugin):
"""
log.debug('check_pre_conditions')
#Lets see if Impress is required (Default is Not wanted)
if int(self.config.get_config(u'Impress', QtCore.Qt.Unchecked)) == QtCore.Qt.Checked:
if int(self.config.get_config(
u'Impress', QtCore.Qt.Unchecked)) == QtCore.Qt.Checked:
try:
if os.name == u'nt':
#Check to see if we are Win32
@ -88,25 +90,27 @@ class PresentationPlugin(Plugin):
openoffice = ImpressController()
self.registerControllers(u'Impress', openoffice)
except:
log.error(u'Reason : %s', sys.exc_info())
log.exception(u'Failed to set up plugin for Impress')
#Lets see if Powerpoint is required (Default is Not wanted)
if int(self.config.get_config(u'Powerpoint', QtCore.Qt.Unchecked)) == QtCore.Qt.Checked:
if int(self.config.get_config(
u'Powerpoint', QtCore.Qt.Unchecked)) == QtCore.Qt.Checked:
try:
#Check to see if we are Win32
from win32com.client import Dispatch
powerpoint = PowerpointController()
self.registerControllers(u'Powerpoint', powerpoint)
except:
log.error(u'Reason : %s', sys.exc_info())
log.exception(u'Failed to set up plugin for Powerpoint')
#Lets see if Powerpoint Viewer is required (Default is Not wanted)
if int(self.config.get_config(u'Powerpoint Viewer', QtCore.Qt.Unchecked)) == QtCore.Qt.Checked:
if int(self.config.get_config(
u'Powerpoint Viewer', QtCore.Qt.Unchecked)) == QtCore.Qt.Checked:
try:
#Check to see if we are Win32
from win32com.client import Dispatch
powerpoint = PowerpointController()
self.registerControllers(u'Powerpoint Viewer', powerpoint)
except:
log.error(u'Reason : %s', sys.exc_info())
log.exception(u'Failed to set up plugin for Powerpoint Viewer')
#If we have no available controllers disable plugin
if len(self.controllers) > 0:
return True

View File

@ -45,6 +45,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
Constructor
"""
QtGui.QDialog.__init__(self, parent)
self.parent = parent
self.setupUi(self)
# Connecting signals and slots
QtCore.QObject.connect(self.AuthorAddButton,
@ -52,13 +53,15 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
QtCore.QObject.connect(self.AuthorRemoveButton,
QtCore.SIGNAL(u'clicked()'), self.onAuthorRemoveButtonClicked)
QtCore.QObject.connect(self.AuthorsListView,
QtCore.SIGNAL(u'itemClicked(QListWidgetItem*)'), self.onAuthorsListViewPressed)
QtCore.SIGNAL(u'itemClicked(QListWidgetItem*)'),
self.onAuthorsListViewPressed)
QtCore.QObject.connect(self.TopicAddButton,
QtCore.SIGNAL(u'clicked()'), self.onTopicAddButtonClicked)
QtCore.QObject.connect(self.TopicRemoveButton,
QtCore.SIGNAL(u'clicked()'), self.onTopicRemoveButtonClicked)
QtCore.QObject.connect(self.TopicsListView,
QtCore.SIGNAL(u'itemClicked(QListWidgetItem*)'), self.onTopicListViewPressed)
QtCore.SIGNAL(u'itemClicked(QListWidgetItem*)'),
self.onTopicListViewPressed)
QtCore.QObject.connect(self.CopyrightInsertButton,
QtCore.SIGNAL(u'clicked()'), self.onCopyrightInsertButtonTriggered)
QtCore.QObject.connect(self.VerseAddButton,
@ -70,11 +73,15 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
QtCore.QObject.connect(self.VerseDeleteButton,
QtCore.SIGNAL(u'clicked()'), self.onVerseDeleteButtonClicked)
QtCore.QObject.connect(self.VerseListWidget,
QtCore.SIGNAL(u'itemClicked(QListWidgetItem*)'), self.onVerseListViewPressed)
QtCore.SIGNAL(u'itemClicked(QListWidgetItem*)'),
self.onVerseListViewPressed)
QtCore.QObject.connect(self.SongbookCombo,
QtCore.SIGNAL(u'activated(int)'), self.onSongBookComboChanged)
QtCore.QObject.connect(self.ThemeSelectionComboItem,
QtCore.SIGNAL(u'activated(int)'), self.onThemeComboChanged)
QtCore.QObject.connect(self.ThemeAddButton,
QtCore.SIGNAL(u'clicked()'),
self.parent.parent.render_manager.theme_manager.onAddTheme)
QtCore.QObject.connect(self.MaintenanceButton,
QtCore.SIGNAL(u'clicked()'), self.onMaintenanceButtonClicked)
QtCore.QObject.connect(self.TitleEditItem,
@ -89,7 +96,6 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
QtCore.SIGNAL(u'lostFocus()'), self.onVerseOrderEditLostFocus)
# Create other objects and forms
self.songmanager = songmanager
self.parent = parent
self.verse_form = EditVerseForm()
self.initialise()
self.AuthorsListView.setSortingEnabled(False)
@ -110,7 +116,8 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
for author in authors:
row = self.AuthorsSelectionComboItem.count()
self.AuthorsSelectionComboItem.addItem(author.display_name)
self.AuthorsSelectionComboItem.setItemData(row, QtCore.QVariant(author.id))
self.AuthorsSelectionComboItem.setItemData(
row, QtCore.QVariant(author.id))
def loadTopics(self):
topics = self.songmanager.get_topics()
@ -165,13 +172,15 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
title = self.song.search_title.split(u'@')
if self.song.song_book_id != 0:
book_name = self.songmanager.get_book(self.song.song_book_id)
id = self.SongbookCombo.findText(unicode(book_name.name), QtCore.Qt.MatchExactly)
id = self.SongbookCombo.findText(
unicode(book_name.name), QtCore.Qt.MatchExactly)
if id == -1:
# Not Found
id = 0
self.SongbookCombo.setCurrentIndex(id)
if self.song.theme_name is not None and len(self.song.theme_name) > 0:
id = self.ThemeSelectionComboItem.findText(unicode(self.song.theme_name), QtCore.Qt.MatchExactly)
id = self.ThemeSelectionComboItem.findText(
unicode(self.song.theme_name), QtCore.Qt.MatchExactly)
if id == -1:
# Not Found
id = 0
@ -272,7 +281,8 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
self.song.song_book_id = 0
else:
item = int(self.SongbookCombo.currentIndex())
self.song.song_book_id = (self.SongbookCombo.itemData(item)).toInt()[0]
self.song.song_book_id = \
(self.SongbookCombo.itemData(item)).toInt()[0]
def onThemeComboChanged(self, item):
if item == 0:
@ -337,7 +347,8 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
def _validate_song(self):
"""
Check the validity of the form. Only display the 'save' if the data can be saved.
Check the validity of the form. Only display the 'save' if the data
can be saved.
"""
log.debug(u'Validate Song')
# Lets be nice and assume the data is correct.
@ -345,26 +356,32 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
message = u''
if len(self.TitleEditItem.displayText()) == 0:
valid = False
##self.TitleEditItem.setStyleSheet(u'background-color: red; color: white')
#self.TitleEditItem.setStyleSheet(
# u'background-color: red; color: white')
self.SongTabWidget.setCurrentIndex(0)
self.TitleEditItem.setFocus()
return False, translate(u'SongFormDialog', u'You need to enter a song title.')
return False, translate(
u'SongFormDialog', u'You need to enter a song title.')
#else:
#self.TitleEditItem.setStyleSheet(u'')
if self.VerseListWidget.count() == 0:
valid = False
#self.VerseListWidget.setStyleSheet(u'background-color: red; color: white')
#self.VerseListWidget.setStyleSheet(
# u'background-color: red; color: white')
self.SongTabWidget.setCurrentIndex(0)
self.VerseListWidget.setFocus()
return False, translate(u'SongFormDialog', u'You need to enter some verses.')
return False, translate(
u'SongFormDialog', u'You need to enter some verses.')
#else:
#self.VerseListWidget.setStyleSheet(u'')
if self.AuthorsListView.count() == 0:
valid = False
#self.AuthorsListView.setStyleSheet(u'background-color: red; color: white')
#self.AuthorsListView.setStyleSheet(
# u'background-color: red; color: white')
self.SongTabWidget.setCurrentIndex(2)
self.AuthorsListView.setFocus()
return False, translate(u'SongFormDialog', u'You need to provide at least one author.')
return False, translate(
u'SongFormDialog', u'You need to provide at least one author.')
#else:
#self.AuthorsListView.setStyleSheet(u'')
return valid, message
@ -406,7 +423,8 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
return
self.song.title = unicode(self.TitleEditItem.displayText())
self.song.copyright = unicode(self.CopyrightEditItem.displayText())
self.song.search_title = unicode(self.TitleEditItem.displayText()) + u'@'+ unicode(self.AlternativeEdit.displayText())
self.song.search_title = unicode(self.TitleEditItem.displayText()) + \
u'@'+ unicode(self.AlternativeEdit.displayText())
self.song.comments = unicode(self.CommentsEdit.toPlainText())
self.song.ccli_number = unicode(self.CCLNumberEdit.displayText())
self.processLyrics()

View File

@ -51,7 +51,8 @@ class SongManager():
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/songs.sqlite' % self.config.get_data_path()
self.db_url = u'sqlite:///%s/songs.sqlite' % \
self.config.get_data_path()
else:
self.db_url = db_type + 'u://' + \
self.config.get_config(u'db username') + u':' + \
@ -88,7 +89,8 @@ class SongManager():
"""
Searches the song authors for keywords.
"""
return self.session.query(Author).filter(Author.display_name.like(u'%' + keywords + u'%')).order_by(Author.display_name.asc()).all()
return self.session.query(Author).filter(Author.display_name.like(
u'%' + keywords + u'%')).order_by(Author.display_name.asc()).all()
def get_song(self, id=None):
"""
@ -109,7 +111,7 @@ class SongManager():
return True
except:
self.session.rollback()
log.error(u'Errow thrown %s', sys.exc_info()[1])
log.exception(u'Could not save song to song database')
return False
def delete_song(self, songid):
@ -120,8 +122,7 @@ class SongManager():
return True
except:
self.session.rollback()
log.error(u'Errow thrown %s', sys.exc_info()[1])
print u'Errow thrown ', sys.exc_info()[1]
log.exception(u'Could not delete song from song database')
return False
def get_authors(self):
@ -146,7 +147,7 @@ class SongManager():
return True
except:
self.session.rollback()
log.error(u'Errow thrown %s', sys.exc_info()[1])
log.exception(u'Could not save author to song database')
return False
def delete_author(self, authorid):
@ -160,7 +161,7 @@ class SongManager():
return True
except:
self.session.rollback()
log.error(u'Errow thrown %s', sys.exc_info()[1])
log.exception(u'Could not delete author from song database')
return False
def get_topics(self):
@ -185,7 +186,7 @@ class SongManager():
return True
except:
self.session.rollback()
log.error(u'Errow thrown %s', sys.exc_info()[1])
log.exception(u'Could not save topic to song database')
return False
def delete_topic(self, topicid):
@ -199,7 +200,7 @@ class SongManager():
return True
except:
self.session.rollback()
log.error(u'Errow thrown %s', sys.exc_info()[1])
log.exception(u'Could not delete topic from song database')
return False
def get_books(self):
@ -224,7 +225,7 @@ class SongManager():
return True
except Exception, e:
self.session.rollback()
log.error(u'Errow thrown %s', e.args[0])
log.exception(u'Could not save book to song database')
return False
def delete_book(self, bookid):
@ -238,5 +239,6 @@ class SongManager():
return True
except:
self.session.rollback()
log.error(u'Errow thrown %s', sys.exc_info()[1])
log.exception(u'Could not delete book from song database')
return False

View File

@ -32,7 +32,7 @@ from openlp.plugins.songs.lib.classes import *
def init_models(url):
engine = create_engine(url)
metadata.bind = engine
session = scoped_session(sessionmaker(autoflush=True,
session = scoped_session(sessionmaker(autoflush=False,
autocommit=False, bind=engine))
mapper(Author, authors_table)
mapper(Book, song_books_table)

View File

@ -49,10 +49,6 @@
<file>import_remove.png</file>
<file>import_load.png</file>
</qresource>
<qresource prefix="audit" >
<file>audit_start.png</file>
<file>audit_stop.png</file>
</qresource>
<qresource prefix="exports" >
<file>export_selectall.png</file>
<file>export_remove.png</file>