diff --git a/openlp/plugins/plugin.txt b/documentation/plugin.txt similarity index 100% rename from openlp/plugins/plugin.txt rename to documentation/plugin.txt diff --git a/openlp/core/lib/__init__.py b/openlp/core/lib/__init__.py index 84525352e..38bcd127c 100644 --- a/openlp/core/lib/__init__.py +++ b/openlp/core/lib/__init__.py @@ -172,7 +172,7 @@ from mediamanageritem import MediaManagerItem from xmlrootclass import XmlRootClass from serviceitem import ServiceItem from serviceitem import ServiceItemType -from serviceitem import ServiceItem +from serviceitem import ItemCapabilities from toolbar import OpenLPToolbar from dockwidget import OpenLPDockWidget from songxmlhandler import SongXMLBuilder, SongXMLParser diff --git a/openlp/core/lib/eventreceiver.py b/openlp/core/lib/eventreceiver.py index 45eeb5145..5b79fc40a 100644 --- a/openlp/core/lib/eventreceiver.py +++ b/openlp/core/lib/eventreceiver.py @@ -109,6 +109,12 @@ class EventReceiver(QtCore.QObject): ``presentation types`` Informs all components of the presentation types supported. + ``blank_check`` + Check to see if th eblank display message is required + + ``version_check`` + Version has changed so pop up window. + """ def __init__(self): """ diff --git a/openlp/core/lib/mediamanageritem.py b/openlp/core/lib/mediamanageritem.py index 5dc14e50e..81d9a5b03 100644 --- a/openlp/core/lib/mediamanageritem.py +++ b/openlp/core/lib/mediamanageritem.py @@ -419,7 +419,7 @@ class MediaManagerItem(QtGui.QWidget): QtGui.QMessageBox.information(self, self.trUtf8('No Service Item Selected'), self.trUtf8('You must select a existing service item to add to.')) - elif self.title == service_item.name: + elif self.title.lower() == service_item.name.lower(): self.generateSlideData(service_item) self.parent.service_manager.addServiceItem(service_item) else: diff --git a/openlp/core/lib/rendermanager.py b/openlp/core/lib/rendermanager.py index 9a621979b..e811529db 100644 --- a/openlp/core/lib/rendermanager.py +++ b/openlp/core/lib/rendermanager.py @@ -49,7 +49,7 @@ class RenderManager(object): """ log.info(u'RenderManager Loaded') - def __init__(self, theme_manager, screens, screen_number=0): + def __init__(self, theme_manager, screens): """ Initialise the render manager. """ @@ -57,7 +57,6 @@ class RenderManager(object): self.screens = screens self.theme_manager = theme_manager self.renderer = Renderer() - self.screens.set_current_display(screen_number) self.calculate_default(self.screens.current[u'size']) self.theme = u'' self.service_theme = u'' @@ -65,12 +64,9 @@ class RenderManager(object): self.override_background = None self.themedata = None - def update_display(self, screen_number): + def update_display(self): """ Updates the render manager's information about the current screen. - - ``screen_number`` - The updated index of the output/display screen. """ log.debug(u'Update Display') self.calculate_default(self.screens.current[u'size']) diff --git a/openlp/core/lib/serviceitem.py b/openlp/core/lib/serviceitem.py index d86597b40..7bb58af2b 100644 --- a/openlp/core/lib/serviceitem.py +++ b/openlp/core/lib/serviceitem.py @@ -42,6 +42,13 @@ class ServiceItemType(object): Image = 2 Command = 3 +class ItemCapabilities(object): + AllowsPreview = 1 + AllowsEdit = 2 + AllowsMaintain = 3 + RequiresMedia = 4 + + class ServiceItem(object): """ The service item is a base class for the plugins to use to interact with @@ -67,14 +74,18 @@ class ServiceItem(object): self.raw_footer = None self.theme = None self.service_item_type = None - self.edit_enabled = False - self.maintain_allowed = False self._raw_frames = [] self._display_frames = [] self._uuid = unicode(uuid.uuid1()) - self.auto_preview_allowed = False self.notes = u'' self.from_plugin = False + self.capabilities = [] + + def add_capability(self, capability): + self.capabilities.append(capability) + + def is_capable(self, capability): + return capability in self.capabilities def addIcon(self, icon): """ @@ -207,10 +218,8 @@ class ServiceItem(object): u'type':self.service_item_type, u'audit':self.audit, u'notes':self.notes, - u'preview':self.auto_preview_allowed, - u'edit':self.edit_enabled, - u'maintain':self.maintain_allowed, - u'from_plugin':self.from_plugin + u'from_plugin':self.from_plugin, + u'capabilities':self.capabilities } service_data = [] if self.service_item_type == ServiceItemType.Text: @@ -244,11 +253,9 @@ class ServiceItem(object): self.addIcon(header[u'icon']) self.raw_footer = header[u'footer'] self.audit = header[u'audit'] - self.auto_preview_allowed = header[u'preview'] self.notes = header[u'notes'] - self.edit_enabled = header[u'edit'] - self.maintain_allowed = header[u'maintain'] self.from_plugin = header[u'from_plugin'] + self.capabilities = header[u'capabilities'] if self.service_item_type == ServiceItemType.Text: for slide in serviceitem[u'serviceitem'][u'data']: self._raw_frames.append(slide) @@ -284,11 +291,8 @@ class ServiceItem(object): """ return self._uuid != other._uuid - def is_song(self): - return self.name.lower() == u'songs' - def is_media(self): - return self.name.lower() == u'media' + return ItemCapabilities.RequiresMedia in self.capabilities def is_command(self): return self.service_item_type == ServiceItemType.Command diff --git a/openlp/core/lib/settingstab.py b/openlp/core/lib/settingstab.py index d22d72750..930ce6bc8 100644 --- a/openlp/core/lib/settingstab.py +++ b/openlp/core/lib/settingstab.py @@ -54,6 +54,7 @@ class SettingsTab(QtGui.QWidget): self.config = PluginConfig(title) else: self.config = PluginConfig(section) + self.preLoad() self.load() def setupUi(self): @@ -62,6 +63,12 @@ class SettingsTab(QtGui.QWidget): """ pass + def preLoad(self): + """ + Setup the tab's interface. + """ + pass + def retranslateUi(self): """ Setup the interface translation strings. diff --git a/openlp/core/test/data_for_tests/render_theme.xml b/openlp/core/test/data_for_tests/render_theme.xml deleted file mode 100644 index 63dfddc02..000000000 --- a/openlp/core/test/data_for_tests/render_theme.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - openlp.org Packaged Theme - 0 - clWhite - - - Tahoma - $00007F - 53 - pixels - 0 - $000000 - 0 - $000000 - 0 - 0 - 1 - diff --git a/openlp/core/test/data_for_tests/snowbig.jpg b/openlp/core/test/data_for_tests/snowbig.jpg deleted file mode 100644 index f1d041927..000000000 Binary files a/openlp/core/test/data_for_tests/snowbig.jpg and /dev/null differ diff --git a/openlp/core/test/data_for_tests/snowsmall.jpg b/openlp/core/test/data_for_tests/snowsmall.jpg deleted file mode 100644 index 3fd506415..000000000 Binary files a/openlp/core/test/data_for_tests/snowsmall.jpg and /dev/null differ diff --git a/openlp/core/test/data_for_tests/sunset1.jpg b/openlp/core/test/data_for_tests/sunset1.jpg deleted file mode 100644 index 75e819c6e..000000000 Binary files a/openlp/core/test/data_for_tests/sunset1.jpg and /dev/null differ diff --git a/openlp/core/test/data_for_tests/treesbig.jpg b/openlp/core/test/data_for_tests/treesbig.jpg deleted file mode 100644 index 9454b3a68..000000000 Binary files a/openlp/core/test/data_for_tests/treesbig.jpg and /dev/null differ diff --git a/openlp/core/test/data_for_tests/treessmall.jpg b/openlp/core/test/data_for_tests/treessmall.jpg deleted file mode 100644 index d52ec6e80..000000000 Binary files a/openlp/core/test/data_for_tests/treessmall.jpg and /dev/null differ diff --git a/openlp/core/test/golden_bitmaps/test_bg_shrink_x.bmp b/openlp/core/test/golden_bitmaps/test_bg_shrink_x.bmp deleted file mode 100644 index c7261c100..000000000 Binary files a/openlp/core/test/golden_bitmaps/test_bg_shrink_x.bmp and /dev/null differ diff --git a/openlp/core/test/golden_bitmaps/test_bg_shrink_y.bmp b/openlp/core/test/golden_bitmaps/test_bg_shrink_y.bmp deleted file mode 100644 index 91adf0188..000000000 Binary files a/openlp/core/test/golden_bitmaps/test_bg_shrink_y.bmp and /dev/null differ diff --git a/openlp/core/test/golden_bitmaps/test_bg_stretch_x.bmp b/openlp/core/test/golden_bitmaps/test_bg_stretch_x.bmp deleted file mode 100644 index 9741a266b..000000000 Binary files a/openlp/core/test/golden_bitmaps/test_bg_stretch_x.bmp and /dev/null differ diff --git a/openlp/core/test/golden_bitmaps/test_bg_stretch_y.bmp b/openlp/core/test/golden_bitmaps/test_bg_stretch_y.bmp deleted file mode 100644 index a05a930d8..000000000 Binary files a/openlp/core/test/golden_bitmaps/test_bg_stretch_y.bmp and /dev/null differ diff --git a/openlp/core/test/golden_bitmaps/test_gradient_h.bmp b/openlp/core/test/golden_bitmaps/test_gradient_h.bmp deleted file mode 100644 index f968fe8b7..000000000 Binary files a/openlp/core/test/golden_bitmaps/test_gradient_h.bmp and /dev/null differ diff --git a/openlp/core/test/golden_bitmaps/test_gradient_v.bmp b/openlp/core/test/golden_bitmaps/test_gradient_v.bmp deleted file mode 100644 index 1b9b434e3..000000000 Binary files a/openlp/core/test/golden_bitmaps/test_gradient_v.bmp and /dev/null differ diff --git a/openlp/core/test/golden_bitmaps/test_theme_basic.bmp b/openlp/core/test/golden_bitmaps/test_theme_basic.bmp deleted file mode 100644 index b156ac762..000000000 Binary files a/openlp/core/test/golden_bitmaps/test_theme_basic.bmp and /dev/null differ diff --git a/openlp/core/test/golden_bitmaps/test_theme_font.bmp b/openlp/core/test/golden_bitmaps/test_theme_font.bmp deleted file mode 100644 index c0f6f3aa5..000000000 Binary files a/openlp/core/test/golden_bitmaps/test_theme_font.bmp and /dev/null differ diff --git a/openlp/core/test/golden_bitmaps/test_theme_horizontal_align_centre.bmp b/openlp/core/test/golden_bitmaps/test_theme_horizontal_align_centre.bmp deleted file mode 100644 index 2c10be95e..000000000 Binary files a/openlp/core/test/golden_bitmaps/test_theme_horizontal_align_centre.bmp and /dev/null differ diff --git a/openlp/core/test/golden_bitmaps/test_theme_horizontal_align_left.bmp b/openlp/core/test/golden_bitmaps/test_theme_horizontal_align_left.bmp deleted file mode 100644 index c7245748e..000000000 Binary files a/openlp/core/test/golden_bitmaps/test_theme_horizontal_align_left.bmp and /dev/null differ diff --git a/openlp/core/test/golden_bitmaps/test_theme_horizontal_align_left_lyric.bmp b/openlp/core/test/golden_bitmaps/test_theme_horizontal_align_left_lyric.bmp deleted file mode 100644 index 8e3fc877a..000000000 Binary files a/openlp/core/test/golden_bitmaps/test_theme_horizontal_align_left_lyric.bmp and /dev/null differ diff --git a/openlp/core/test/golden_bitmaps/test_theme_horizontal_align_right.bmp b/openlp/core/test/golden_bitmaps/test_theme_horizontal_align_right.bmp deleted file mode 100644 index 7d404a85e..000000000 Binary files a/openlp/core/test/golden_bitmaps/test_theme_horizontal_align_right.bmp and /dev/null differ diff --git a/openlp/core/test/golden_bitmaps/test_theme_shadow_outline.bmp b/openlp/core/test/golden_bitmaps/test_theme_shadow_outline.bmp deleted file mode 100644 index daa1e07dd..000000000 Binary files a/openlp/core/test/golden_bitmaps/test_theme_shadow_outline.bmp and /dev/null differ diff --git a/openlp/core/test/golden_bitmaps/test_theme_vertical_align_bot.bmp b/openlp/core/test/golden_bitmaps/test_theme_vertical_align_bot.bmp deleted file mode 100644 index d43698b9f..000000000 Binary files a/openlp/core/test/golden_bitmaps/test_theme_vertical_align_bot.bmp and /dev/null differ diff --git a/openlp/core/test/golden_bitmaps/test_theme_vertical_align_cen.bmp b/openlp/core/test/golden_bitmaps/test_theme_vertical_align_cen.bmp deleted file mode 100644 index be19a7288..000000000 Binary files a/openlp/core/test/golden_bitmaps/test_theme_vertical_align_cen.bmp and /dev/null differ diff --git a/openlp/core/test/golden_bitmaps/test_theme_vertical_align_top.bmp b/openlp/core/test/golden_bitmaps/test_theme_vertical_align_top.bmp deleted file mode 100644 index c7245748e..000000000 Binary files a/openlp/core/test/golden_bitmaps/test_theme_vertical_align_top.bmp and /dev/null differ diff --git a/openlp/core/test/test_mediamanageritem.py b/openlp/core/test/test_mediamanageritem.py deleted file mode 100644 index a80bcdb64..000000000 --- a/openlp/core/test/test_mediamanageritem.py +++ /dev/null @@ -1,110 +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, Christian Richter, 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 os -import sys - -from PyQt4 import QtCore, QtGui - -from openlp.core.lib import MediaManagerItem - -logging.basicConfig(level=logging.DEBUG, - format='%(asctime)s %(name)-30s %(levelname)-8s %(message)s', - datefmt='%m-%d %H:%M', - filename='plugins.log', - filemode='w') - -console=logging.StreamHandler() -# set a format which is simpler for console use -formatter = logging.Formatter(u'%(name)24s: %(levelname)-8s %(message)s') -# tell the handler to use this format -console.setFormatter(formatter) -logging.getLogger(u'').addHandler(console) -log = logging.getLogger(u'') -logging.info(u'Logging started') -mypath = os.path.split(os.path.abspath(__file__))[0] -sys.path.insert(0,(os.path.join(mypath, '..' ,'..', '..'))) - -class TestMediaManager: - def setup_class(self): - self.app = QtGui.QApplication([]) - logging.info (u'App is ' + unicode(self.app)) - self.main_window = QtGui.QMainWindow() - self.main_window.resize(200, 600) - self.MediaManagerDock = QtGui.QDockWidget(self.main_window) - sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, - QtGui.QSizePolicy.Expanding) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth( - self.MediaManagerDock.sizePolicy().hasHeightForWidth()) - self.MediaManagerDock.setSizePolicy(sizePolicy) - icon = QtGui.QIcon() - icon.addPixmap(QtGui.QPixmap(u':/system/system_mediamanager.png'), - QtGui.QIcon.Normal, QtGui.QIcon.Off) - self.MediaManagerDock.setWindowIcon(icon) - self.MediaManagerDock.setFloating(False) - self.MediaManagerContents = QtGui.QWidget() - sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, - QtGui.QSizePolicy.Expanding) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth( - self.MediaManagerContents.sizePolicy().hasHeightForWidth()) - self.MediaManagerContents.setSizePolicy(sizePolicy) - self.MediaManagerLayout = QtGui.QHBoxLayout(self.MediaManagerContents) - self.MediaManagerLayout.setContentsMargins(0, 2, 0, 0) - self.MediaToolBox = QtGui.QToolBox(self.MediaManagerContents) - self.MediaManagerDock.setWidget(self.MediaManagerContents) - self.main_window.addDockWidget(QtCore.Qt.DockWidgetArea(1), - self.MediaManagerDock) - self.MediaManagerLayout.addWidget(self.MediaToolBox) - def test1(self): - log=logging.getLogger(u'test1') - log.info(u'Start') - i1=MediaManagerItem(self.MediaToolBox) - i2=MediaManagerItem(self.MediaToolBox) - log.info(u'i1'+unicode(i1)) - log.info(u'i2'+unicode(i2)) - i1.addToolbar() - i1.addToolbarButton(u'Test1', u'Test1', None) - i2.addToolbar() - i2.addToolbarButton(u'Test2', u'Test2', None) - self.MediaToolBox.setItemText( - self.MediaToolBox.indexOf(i1), self.trUtf8('Item1')) - self.MediaToolBox.setItemText( - self.MediaToolBox.indexOf(i2), self.trUtf8('Item2')) - log.info(u'Show window') - self.main_window.show() - log.info(u'End') - return 1 - -if __name__ == "__main__": - t=TestMediaManager() - t.setup_class() - t.test1() - log.info(u'exec') - sys.exit(t.app.exec_()) diff --git a/openlp/core/test/test_plugin_manager.py b/openlp/core/test/test_plugin_manager.py deleted file mode 100644 index c927fce9b..000000000 --- a/openlp/core/test/test_plugin_manager.py +++ /dev/null @@ -1,74 +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, Christian Richter, 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 os -import sys - -from openlp.core.lib.pluginmanager import PluginManager - -logging.basicConfig(level=logging.DEBUG, - format='%(asctime)s %(name)-12s %(levelname)-8s %(message)s', - datefmt='%m-%d %H:%M', - filename='plugins.log', - filemode='w') - -console=logging.StreamHandler() -# set a format which is simpler for console use -formatter = logging.Formatter(u'%(name)-12s: %(levelname)-8s %(message)s') -# tell the handler to use this format -console.setFormatter(formatter) -logging.getLogger(u'').addHandler(console) -log = logging.getLogger(u'') -logging.info(u'Logging started') -mypath = os.path.split(os.path.abspath(__file__))[0] -sys.path.insert(0,(os.path.join(mypath, '..' ,'..', '..'))) - -# test the plugin manager with some plugins in the test_plugins directory -class TestPluginManager: - def test_init(self): - self.p = PluginManager(u'./testplugins') - p = self.p - p.find_plugins(u'./testplugins', None, None) - assert(len(p.plugins) == 2) - # get list of the names of the plugins - names = [plugin.name for plugin in p.plugins] - # see which ones we've got - assert(u'testplugin1' in names) - assert(u'testplugin2' in names) - # and not got - it's too deep in the hierarchy! - assert(u'testplugin3' not in names) - # test that the weighting is done right - assert(p.plugins[0].name == "testplugin2") - assert(p.plugins[1].name == "testplugin1") - -if __name__ == "__main__": - log.debug(u'Starting') - t = TestPluginManager() - t.test_init() - log.debug(u'List of plugins found:') - for plugin in t.p.plugins: - log.debug(u'Plugin %s, name=%s (version=%d)' %(unicode(plugin), - plugin.name, plugin.version)) diff --git a/openlp/core/test/test_render.py b/openlp/core/test/test_render.py deleted file mode 100644 index 92f79cf37..000000000 --- a/openlp/core/test/test_render.py +++ /dev/null @@ -1,241 +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, Christian Richter, 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 sys -import os -import os.path - -from PyQt4 import QtGui, QtCore - -from openlp.core.theme import Theme -from openlp.core.lib import Renderer - -mypath = os.path.split(os.path.abspath(__file__))[0] -sys.path.insert(0, (os.path.join(mypath, '..', '..', '..'))) - -# from http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/66062 -def whoami(depth=1): - return sys._getframe(depth).f_code.co_name - -class TstFrame: - # {{{ init - - def __init__(self, size): - """Create the DemoPanel.""" - self.width = size.width(); - self.height = size.height(); - # create something to be painted into - self._Buffer = QtGui.QPixmap(self.width, self.height) - def GetPixmap(self): - return self._Buffer - - # }}} - -class TestRender_base: - def __init__(self): - if not os.path.exists(u'test_results'): - os.mkdir(u'test_results') - self.app = None - def write_to_file(self, pixmap, name): - im=pixmap.toImage() - testpathname = os.path.join(u'test_results', name+'.bmp') - if os.path.exists(testpathname): - os.unlink(testpathname) - im.save(testpathname, 'bmp') - return im - # xxx quitting the app still leaves it hanging aroudn so we die - # when trying to start another one. Not quitting doesn't help - # though This means that the py.test runs both test modules in - # sequence and the second one tries to create another application - # which gives us errors :( - - def setup_class(self): - print "class setup", self - try: - if self.app is None: - pass - except AttributeError: # didn't have one - print "No app" - self.app = None - - print "Test app (should be None)" - if self.app is None: - print "App is None" - self.app = QtGui.QApplication([]) - else: - print "class setup, app is", app -# self.app = QtGui.QApplication([]) - - def teardown_class(self): - print "class quit", self, self.app - self.app.quit() - - def setup_method(self, method): - print "SSsetup", method - if not hasattr(self, 'app'): - self.app = None - try: # see if we already have an app for some reason. - # have to try and so something, cant just test against None - print "app", self.app, ";;;" - print self.app.quit() - print "quitted" - except RuntimeError: # not valid app, create one - print "Runtime error" - except AttributeError: # didn't have one - print "Attribute error" -# print "App", self.app -# self.app = QtGui.QApplication([]) - print "Application created and sorted" - self.size = QtCore.QSize(800,600) - frame = TstFrame(size = self.size) - self.frame = frame - self.paintdest = frame.GetPixmap() - self.renderer = Renderer() - self.renderer.set_paint_dest(self.paintdest) - self.expected_answer = "Don't know yet" - self.answer = None - print "--------------- Setup Done -------------" - - def teardown_method(self, method): - self.write_to_file(self.frame.GetPixmap(), 'test_render') - -class TestRender(TestRender_base): - def __init__(self): - TestRender_base.__init__(self) - - def setup_method(self, method): - TestRender_base.setup_method(self, method) - self.renderer.set_debug(1) - themefile = os.path.abspath(u'data_for_tests/render_theme.xml') - self.renderer.set_theme(Theme(themefile)) # set default theme - self.renderer._render_background() - self.renderer.set_text_rectangle(QtCore.QRect( - 0,0, self.size.width()-1, self.size.height()-1)) - self.msg = None - - def test_easy(self): - answer = self.renderer._render_single_line( - u'Test line', tlcorner = (0,100)) - assert(answer == (219,163)) - - def test_longer(self): - answer = self.renderer._render_single_line( - u'Test line with more words than fit on one line', - tlcorner = (10,10)) - assert(answer == (753,136)) - - def test_even_longer(self): - answer = self.renderer._render_single_line( - u'Test line with more words than fit on either one or two lines', - tlcorner = (10,10)) - assert(answer == (753,199)) - def test_lines(self): - lines = [] - lines.append(u'Line One') - lines.append(u'Line Two') - lines.append(u'Line Three and should be long enough to wrap') - lines.append(u'Line Four and should be long enough to wrap also') - answer = self.renderer._render_lines(lines) - assert(answer == QtCore.QRect(0,0,741,378)) - - def test_set_words_openlp(self): - words=""" -Verse 1: Line 1 -Line 2 - -Verse 2: Line 1 -Line 2 - -Verse 3: Line 1 -Line 2 -Line 3""" - expected_answer = ["Verse 1: Line 1\nLine 2","Verse 2: Line 1\nLine 2","Verse 3: Line 1\nLine 2\nLine 3"] - answer = self.renderer.set_words_openlp(words) - assert(answer == expected_answer) - - def test_render_screens(self): - words=""" -Verse 1: Line 1 -Line 2 - -Verse 2: Line 1 -Line 2 - -Verse 3: Line 1 -Line 2 -Line 3""" - verses = self.renderer.set_words_openlp(words) - expected_answer = ["Verse 1: Line 1\nLine 2","Verse 2: Line 1\nLine 2","Verse 3: Line 1\nLine 2\nLine 3"] - assert(verses == expected_answer) - - expected_answer = [QtCore.QRect(0,0,397,126), QtCore.QRect(0,0,397,126), - QtCore.QRect(0,0,397,189)] - for v in range(len(verses)): - answer=self.renderer.render_screen(v) -# print v, answer.x(), answer.y(), answer.width(), answer.height() - assert(answer == expected_answer[v]) - - def split_test(self, number, answer, expected_answers): - lines=[] - print "Split test", number, answer - for i in range(number): - extra="" - if i == 51: # make an extra long line on line 51 to test wrapping - extra = "Some more words to make it wrap around don't you know until it wraps so many times we don't know what to do" - lines.append(u'Line %d %s' % (i, extra)) - result = self.renderer.split_set_of_lines(lines) - print "results---------------__", result - for i in range(len(result)): - self.setup_method(None) - answer = self.renderer._render_lines(result[i]) - print answer - self.write_to_file(self.frame.GetPixmap(), "split_test_%03d"% i) - print number, i, answer.x(), answer.y(), answer.width(), \ - answer.height() - e = expected_answers[i] - assert(answer == QtCore.QRect(e[0],e[1],e[2],e[3])) - - - def test_splits(self): - print "Test splits" - self.split_test(100, 11, [(0,0,180,567), (0,0,214,567), (0,0,214,567), - (0,0,214,567), (0,0,214,567), (0,0,214,378), (0,0,759,567), - (0,0,214,567), (0,0,214,567), (0,0,214,567), (0,0,214,567), - (0,0,214,567), (0,0,214,567)]) - self.split_test(30, 4, [ (0,0,180,441), (0,0,214,441), (0,0,214,441), - (0,0,214,441)]) - self.split_test(20, 3, [(0,0,180,378), (0,0,214,378), (0,0,214,378)]) - self.split_test(12, 2, [(0,0,180,378), (0,0,214,378)]) - self.split_test(4, 1, [(0,0,180,252)]) - self.split_test(6, 1, [(0,0,180,378)]) - self.split_test(8, 1, [(0,0,180,504)]) - -if __name__ == "__main__": - t = TestRender() - t.setup_class() - t.setup_method(None) - t.test_easy() - t.test_splits() - t.teardown_method(None) diff --git a/openlp/core/test/test_render_theme.py b/openlp/core/test/test_render_theme.py deleted file mode 100644 index 2b5d1a2b5..000000000 --- a/openlp/core/test/test_render_theme.py +++ /dev/null @@ -1,319 +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, Christian Richter, 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 sys -import os - -from PyQt4 import QtGui, QtCore - -from openlp.core.theme import Theme -from test_render import TestRender_base, whoami - -pypath = os.path.split(os.path.abspath(__file__))[0] -sys.path.insert(0, (os.path.join(mypath, '..', '..', '..'))) - -def compare_images(goldenim, testim, threshold=0.01): - # easy test first - if goldenim == testim: - return 1 - # how close are they? Calculated the sum of absolute differences in - # each channel of each pixel and divide by the number of pixels in the image - # if this sum is < threshold, the images are deemed to be "close enough" - sad = 0; - for x in range(goldenim.width()): - for y in range(goldenim.height()): - p1=goldenim.pixel(x,y) - p2=testim.pixel(x,y) - sad += abs((p1&0xFF)-(p2&0xFF)) - sad += abs((p1>>8&0xFF)-(p2>>8&0xFF)) - sad += abs((p1>>16&0xFF)-(p2>>16&0xFF)) - sad /= float(goldenim.width()*goldenim.height()) - if (sad < threshold): - return 1 - return 0 - -class TestRenderTheme(TestRender_base): - # {{{ Basics - - def __init__(self): - TestRender_base.__init__(self) - - def setup_method(self, method): - TestRender_base.setup_method(self, method) - print "Theme setup", method -# print "setup theme" - self.renderer.set_theme(Theme(u'blank_theme.xml')) # set "blank" theme - self.renderer.set_text_rectangle(QtCore.QRect(0,0, self.size.width(), - self.size.height())) - words = """How sweet the name of Jesus sounds -In a believer's ear! -It soothes his sorrows, heals his wounds, -And drives away his fear. -""" - verses = self.renderer.set_words_openlp(words) -# usually the same - self.expected_answer = QtCore.QRect(0, 0, 559, 342) - self.msg = None - self.bmpname = "Not set a bitmap yet" - print "------------- setup done --------------" - - def teardown_method(self, method): - print "============ teardown =============", method, self.bmpname - if self.bmpname is not None: - assert (self.compare_DC_to_file(self.bmpname)) - if self.expected_answer is not None: # result=None => Nothing to check - assert self.expected_answer == self.answer - print "============ teardown done =========" - - def compare_DC_to_file(self, name): - """writes DC out to a bitmap file and then compares it with a golden - one returns True if OK, False if not (so you can assert on it) - - """ - print "--- compare DC to file --- ", name - p = self.frame.GetPixmap() - im = self.write_to_file(p, name) - print "Compare" - goldenfilename=os.path.join(u'golden_bitmaps",name+".bmp') - if os.path.exists(goldenfilename): - goldenim = QtGui.QImage(goldenfilename) - else: - print "File", goldenfilename, "not found" - return False - if (compare_images(goldenim, im)): - print name, "Images match" - return True - else: - print name, goldenfilename, "Images don't match" - return False - - def test_theme_basic(self): - self.answer = self.renderer.render_screen(0) - self.bmpname = whoami() - print self.renderer._theme.FontProportion - print self.answer, self.expected_answer, \ - self.answer == self.expected_answer -# self.msg=self.bmpname - - # }}} - - # {{{ Gradients - def test_gradient_h(self): - # normally we wouldn't hack with these directly! - self.renderer._theme.BackgroundType = 1 - self.renderer._theme.BackgroundParameter1 = QtGui.QColor(255,0,0) - self.renderer._theme.BackgroundParameter2 = QtGui.QColor(255,255,0) - self.renderer._theme.BackgroundParameter3 = 1 - self.answer = self.renderer.render_screen(0) - self.bmpname = whoami() - - def test_gradient_v(self): - # normally we wouldn't hack with these directly! - self.renderer._theme.BackgroundType = 1 - self.renderer._theme.BackgroundParameter1 = QtGui.QColor(255,0,0) - self.renderer._theme.BackgroundParameter2 = QtGui.QColor(255,255,0) - self.renderer._theme.BackgroundParameter3 = 0 - self.answer = self.renderer.render_screen(0) - self.bmpname = whoami() - # }}} - - # {{{ backgrounds - def test_bg_stretch_y(self): - t = Theme(u'blank_theme.xml') - t.BackgroundType = 2 - t.BackgroundParameter1 = os.path.join(u'data_for_tests', - 'snowsmall.jpg') - t.BackgroundParameter2 = QtGui.QColor(0,0,64) - t.BackgroundParameter3 = 0 - t.Name = "stretch y" - self.renderer.set_theme(t) - print "render" - self.answer = self.renderer.render_screen(0) - print "whoami" - self.bmpname = whoami() - print "fone" - - def test_bg_shrink_y(self): - t = Theme(u'blank_theme.xml') - t.BackgroundType = 2 - t.BackgroundParameter1 = os.path.join(u'data_for_tests', 'snowbig.jpg') - t.BackgroundParameter2 = QtGui.QColor(0,0,64) - t.BackgroundParameter3 = 0 - t.Name = "shrink y" - self.renderer.set_theme(t) - self.answer = self.renderer.render_screen(0) - self.bmpname = whoami() - - def test_bg_stretch_x(self): - t = Theme(u'blank_theme.xml') - t.BackgroundType = 2 - t.BackgroundParameter1 = os.path.join(u'data_for_tests', - 'treessmall.jpg') - t.BackgroundParameter2 = QtGui.QColor(0,0,64) - t.BackgroundParameter3 = 0 - t.VerticalAlign = 2 - t.Name = "stretch x" - self.renderer.set_theme(t) - self.answer = self.renderer.render_screen(0) - self.expected_answer = QtCore.QRect(0, 129, 559, 342) - self.bmpname = whoami() - - def test_bg_shrink_x(self): - t = Theme(u'blank_theme.xml') - t.BackgroundType = 2 - t.BackgroundParameter1 = os.path.join(u'data_for_tests', - 'treesbig.jpg') - t.BackgroundParameter2 = QtGui.QColor(0,0,64) - t.BackgroundParameter3 = 0 - t.VerticalAlign = 2 - t.Name = "shrink x" - self.renderer.set_theme(t) - self.expected_answer = QtCore.QRect(0, 129, 559, 342) - self.answer = self.renderer.render_screen(0) - self.bmpname = whoami() - # }}} - - # {{{ Vertical alignment - def test_theme_vertical_align_top(self): - t = Theme(u'blank_theme.xml') - t.BackgroundType = 0 - t.BackgroundParameter1 = QtGui.QColor(0,0,64) - t.VerticalAlign = 0 - t.Name = "valign top" - self.renderer.set_theme(t) - self.answer = self.renderer.render_screen(0) - self.bmpname = whoami() - - def test_theme_vertical_align_bot(self): - t = Theme(u'blank_theme.xml') - t.BackgroundType = 0 - t.BackgroundParameter1 = QtGui.QColor(0,0,64) - t.VerticalAlign = 1 - t.Name = "valign bot" - self.renderer.set_theme(t) - self.answer = self.renderer.render_screen(0) - self.expected_answer = QtCore.QRect(0, 257, 559, 342) - self.bmpname = whoami() - - def test_theme_vertical_align_cen(self): - t = Theme(u'blank_theme.xml') - t.BackgroundType = 0 - t.BackgroundParameter1 = QtGui.QColor(0,0,64) - t.VerticalAlign = 2 - t.Name = "valign cen" - self.renderer.set_theme(t) - self.answer = self.renderer.render_screen(0) - self.expected_answer = QtCore.QRect(0, 129, 559, 342) - self.bmpname = whoami() - # }}} - - # {{{ Horzontal alignment - def test_theme_horizontal_align_left(self): - t = Theme(u'blank_theme.xml') - t.BackgroundType = 0 - t.BackgroundParameter1 = QtGui.QColor(0,0,64) - t.VerticalAlign = 0 - t.HorizontalAlign = 0 - t.Name = "halign left" - self.renderer.set_theme(t) - self.answer = self.renderer.render_screen(0) - self.bmpname = whoami() - - def test_theme_horizontal_align_right(self): - t = Theme(u'blank_theme.xml') - t.BackgroundType = 0 - t.BackgroundParameter1 = QtGui.QColor(0,0,64) - t.VerticalAlign = 0 - t.HorizontalAlign = 1 - t.Name = "halign right" - self.renderer.set_theme(t) - self.expected_answer = QtCore.QRect(0, 0, 800, 342) - self.answer = self.renderer.render_screen(0) - self.bmpname = whoami() - - def test_theme_horizontal_align_centre(self): - t = Theme(u'blank_theme.xml') - t.BackgroundType = 0 - t.BackgroundParameter1 = QtGui.QColor(0,0,64) - t.VerticalAlign = 0 - t.HorizontalAlign = 2 - t.Name = "halign centre" - self.renderer.set_theme(t) - self.answer = self.renderer.render_screen(0) - self.expected_answer = QtCore.QRect(0, 0, 679, 342) - self.bmpname = whoami() - - def test_theme_horizontal_align_left_lyric(self): - t = Theme(u'blank_theme.xml') - t.BackgroundType = 0 - t.BackgroundParameter1 = QtGui.QColor(0,0,64) - t.VerticalAlign = 0 - t.HorizontalAlign = 0 - t.WrapStyle = 1 - t.Name = "halign left lyric" - self.renderer.set_theme(t) - self.answer = self.renderer.render_screen(0) - self.expected_answer = QtCore.QRect(0, 0, 778, 342) - self.bmpname = whoami() - # }}} - - # {{{ Shadows and outlines - def test_theme_shadow_outline(self): - t = Theme(u'blank_theme.xml') - - t.BackgroundType = 0 - t.BackgroundParameter1 = QtGui.QColor(0,0,0); - t.Name="shadow/outline" - t.Shadow = 1 - t.Outline = 1 - t.ShadowColor = QtGui.QColor(64,128,0) - t.OutlineColor = QtGui.QColor(128,0,0) - self.renderer.set_debug(1) - self.renderer.set_theme(t) - self.answer = self.renderer.render_screen(0) - hoffset = self.renderer._shadow_offset+2*(self.renderer._outline_offset) - voffset = hoffset * (len(self.renderer.words[0])+1) - - self.expected_answer = QtCore.QRect(0, 0, 559+hoffset, 342+voffset) - self.bmpname = whoami() - # }}} - - def test_theme_font(self): - t = Theme(u'blank_theme.xml') - t.BackgroundType = 0 - t.BackgroundParameter1 = QtGui.QColor(0,0,64) - t.Name = "font" - t.FontName = "Times New Roman" - self.renderer.set_theme(t) - self.answer = self.renderer.render_screen(0) - self.expected_answer = QtCore.QRect(0, 0, 499, 336) - self.bmpname=whoami() - -if __name__ == "__main__": - test_render_theme = TestRenderTheme() - test_render_theme.setup_class() - test_render_theme.setup_method(None) - test_render_theme.test_bg_stretch_y() - test_render_theme.teardown_method(None) diff --git a/openlp/core/test/testplugins/deeper/__init__.py b/openlp/core/test/testplugins/deeper/__init__.py deleted file mode 100644 index 8b1378917..000000000 --- a/openlp/core/test/testplugins/deeper/__init__.py +++ /dev/null @@ -1 +0,0 @@ - diff --git a/openlp/core/test/testplugins/deeper/toodeep/__init__.py b/openlp/core/test/testplugins/deeper/toodeep/__init__.py deleted file mode 100644 index 8b1378917..000000000 --- a/openlp/core/test/testplugins/deeper/toodeep/__init__.py +++ /dev/null @@ -1 +0,0 @@ - diff --git a/openlp/core/test/testplugins/deeper/toodeep/plugin3toodeep.py b/openlp/core/test/testplugins/deeper/toodeep/plugin3toodeep.py deleted file mode 100644 index 9746dbdd2..000000000 --- a/openlp/core/test/testplugins/deeper/toodeep/plugin3toodeep.py +++ /dev/null @@ -1,13 +0,0 @@ -from openlp.core.lib import Plugin -import logging - -class testplugin3toodeep(Plugin): - name="testplugin3" - version=0 - global log - log=logging.getLogger(u'testplugin1') - log.info(u'Started') - weight=10 - def __init__(self): - pass - \ No newline at end of file diff --git a/openlp/core/test/testplugins/testplugin1.py b/openlp/core/test/testplugins/testplugin1.py deleted file mode 100644 index 01ae468e6..000000000 --- a/openlp/core/test/testplugins/testplugin1.py +++ /dev/null @@ -1,13 +0,0 @@ -from openlp.core.lib import Plugin -import logging - -class testplugin1(Plugin): - name="testplugin1" - version=0 - global log - log=logging.getLogger(u'testplugin1') - log.info(u'Started') - weight=10 - def __init__(self): - pass - \ No newline at end of file diff --git a/openlp/core/test/testplugins/testplugin2/__init__.py b/openlp/core/test/testplugins/testplugin2/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/openlp/core/test/testplugins/testplugin2/testplugin2.py b/openlp/core/test/testplugins/testplugin2/testplugin2.py deleted file mode 100644 index c1687d2d9..000000000 --- a/openlp/core/test/testplugins/testplugin2/testplugin2.py +++ /dev/null @@ -1,8 +0,0 @@ -from openlp.core.lib import Plugin - -class testplugin2(Plugin): - name="testplugin2" - version=1 - weight=1 - def __init__(self): - pass diff --git a/openlp/core/theme/test/test_theme.py b/openlp/core/theme/test/test_theme.py deleted file mode 100644 index 2e8c2b500..000000000 --- a/openlp/core/theme/test/test_theme.py +++ /dev/null @@ -1,82 +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, Christian Richter, 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 os.path -import sys - -from PyQt4 import QtGui - -from openlp.core.theme import Theme - -mypath = os.path.split(os.path.abspath(__file__))[0] -sys.path.insert(0, (os.path.join(mypath, '..', '..', '..', '..'))) - -print sys.path - -def test_read_theme(): - dir = os.path.split(__file__)[0] - # test we can read a theme - theme = Theme(os.path.join(dir, 'test_theme.xml')) - print theme - assert(theme.BackgroundParameter1 == 'sunset1.jpg') - assert(theme.BackgroundParameter2 is None) - assert(theme.BackgroundParameter3 is None) - assert(theme.BackgroundType == 2) - assert(theme.FontColor == QtGui.QColor(255,255,255)) - assert(theme.FontName == 'Tahoma') - assert(theme.FontProportion == 16) - assert(theme.FontUnits == 'pixels') - assert(theme.HorizontalAlign == 2) - assert(theme.Name == 'openlp.org Packaged Theme') - assert(theme.Outline == -1) - assert(theme.OutlineColor == QtGui.QColor(255,0,0)) - assert(theme.Shadow == -1) - assert(theme.ShadowColor == QtGui.QColor(0,0,1)) - assert(theme.VerticalAlign == 0) - -def test_theme(): - # test we create a "blank" theme correctly - theme = Theme() - print theme - assert(theme.BackgroundParameter1 == QtGui.QColor(0,0,0)) - assert(theme.BackgroundParameter2 is None) - assert(theme.BackgroundParameter3 is None) - assert(theme.BackgroundType == 0) - assert(theme.FontColor == QtGui.QColor(255,255,255)) - assert(theme.FontName == 'Arial') - assert(theme.FontProportion == 30) - assert(theme.HorizontalAlign == 0) - assert(theme.FontUnits == 'pixels') - assert(theme.Name == 'BlankStyle') - assert(theme.Outline == 0) - assert(theme.Shadow == 0) - assert(theme.VerticalAlign == 0) - - print "Tests passed" - -if __name__ == "__main__": - test_read_theme() - test_theme() diff --git a/openlp/core/theme/test/test_theme.xml b/openlp/core/theme/test/test_theme.xml deleted file mode 100644 index 79bc2107f..000000000 --- a/openlp/core/theme/test/test_theme.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - openlp.org Packaged Theme - 2 - sunset1.jpg - - - Tahoma - clWhite - 16 - pixels - -1 - $00000001 - -1 - clRed - 2 - 0 - diff --git a/openlp/core/ui/generaltab.py b/openlp/core/ui/generaltab.py index c6a544430..ec20650cf 100644 --- a/openlp/core/ui/generaltab.py +++ b/openlp/core/ui/generaltab.py @@ -25,16 +25,29 @@ from PyQt4 import QtCore, QtGui -from openlp.core.lib import SettingsTab, str_to_bool +from openlp.core.lib import SettingsTab, str_to_bool, Receiver class GeneralTab(SettingsTab): """ GeneralTab is the general settings tab in the settings dialog. """ - def __init__(self, screen_list): - self.screen_list = screen_list + def __init__(self, screens): + self.screens = screens SettingsTab.__init__(self, u'General') + def preLoad(self): + """ + Set up the display screen and set correct screen + values. + If not set before default to last screen. + """ + self.MonitorNumber = int(self.config.get_config(u'monitor', + self.screens.monitor_number)) + self.screens.set_current_display(self.MonitorNumber) + self.screens.monitor_number = self.MonitorNumber + self.DisplayOnMonitor = str_to_bool(self.config.get_config(u'display on monitor', u'True')) + self.screens.display = self.DisplayOnMonitor + def setupUi(self): self.setObjectName(u'GeneralTab') self.tabTitleVisible = self.trUtf8('General') @@ -60,6 +73,10 @@ class GeneralTab(SettingsTab): self.MonitorComboBox = QtGui.QComboBox(self.MonitorGroupBox) self.MonitorComboBox.setObjectName(u'MonitorComboBox') self.MonitorLayout.addWidget(self.MonitorComboBox) + self.MonitorLayout.addWidget(self.MonitorComboBox) + self.DisplayOnMonitorCheck = QtGui.QCheckBox(self.MonitorGroupBox) + self.DisplayOnMonitorCheck.setObjectName(u'MonitorComboBox') + self.MonitorLayout.addWidget(self.DisplayOnMonitorCheck) self.GeneralLeftLayout.addWidget(self.MonitorGroupBox) self.StartupGroupBox = QtGui.QGroupBox(self.GeneralLeftWidget) self.StartupGroupBox.setObjectName(u'StartupGroupBox') @@ -133,6 +150,8 @@ class GeneralTab(SettingsTab): self.GeneralLayout.addWidget(self.GeneralRightWidget) QtCore.QObject.connect(self.MonitorComboBox, QtCore.SIGNAL(u'activated(int)'), self.onMonitorComboBoxChanged) + QtCore.QObject.connect(self.DisplayOnMonitorCheck, + QtCore.SIGNAL(u'stateChanged(int)'), self.onDisplayOnMonitorCheckChanged) QtCore.QObject.connect(self.WarningCheckBox, QtCore.SIGNAL(u'stateChanged(int)'), self.onWarningCheckBoxChanged) QtCore.QObject.connect(self.AutoOpenCheckBox, @@ -153,6 +172,7 @@ class GeneralTab(SettingsTab): def retranslateUi(self): self.MonitorGroupBox.setTitle(self.trUtf8('Monitors')) self.MonitorLabel.setText(self.trUtf8('Select monitor for output display:')) + self.DisplayOnMonitorCheck.setText(self.trUtf8('Display if in single screen')) self.StartupGroupBox.setTitle(self.trUtf8('Application Startup')) self.WarningCheckBox.setText(self.trUtf8('Show blank screen warning')) self.AutoOpenCheckBox.setText(self.trUtf8('Automatically open the last service')) @@ -168,6 +188,9 @@ class GeneralTab(SettingsTab): def onMonitorComboBoxChanged(self): self.MonitorNumber = self.MonitorComboBox.currentIndex() + def onDisplayOnMonitorCheckChanged(self, value): + self.DisplayOnMonitor = (value == QtCore.Qt.Checked) + def onAutoOpenCheckBoxChanged(self, value): self.AutoOpen = (value == QtCore.Qt.Checked) @@ -193,13 +216,12 @@ class GeneralTab(SettingsTab): self.Password = self.PasswordEdit.displayText() def load(self): - for screen in self.screen_list.screen_list: + for screen in self.screens.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')) self.MonitorComboBox.addItem(screen_name) # Get the configs - self.MonitorNumber = int(self.config.get_config(u'monitor', u'0')) self.Warning = str_to_bool(self.config.get_config(u'blank warning', u'False')) 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')) @@ -211,6 +233,7 @@ class GeneralTab(SettingsTab): self.SaveCheckServiceCheckBox.setChecked(self.PromptSaveService) # Set a few things up self.MonitorComboBox.setCurrentIndex(self.MonitorNumber) + self.DisplayOnMonitorCheck.setChecked(self.DisplayOnMonitor) self.WarningCheckBox.setChecked(self.Warning) self.AutoOpenCheckBox.setChecked(self.AutoOpen) self.ShowSplashCheckBox.setChecked(self.ShowSplash) @@ -221,6 +244,7 @@ class GeneralTab(SettingsTab): def save(self): self.config.set_config(u'monitor', self.MonitorNumber) + self.config.set_config(u'display on monitor', self.DisplayOnMonitor) self.config.set_config(u'blank warning', self.Warning) self.config.set_config(u'auto open', self.AutoOpen) self.config.set_config(u'show splash', self.ShowSplash) @@ -229,3 +253,9 @@ class GeneralTab(SettingsTab): 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.screens.display = self.DisplayOnMonitor + #Monitor Number has changed. + if self.screens.monitor_number != self.MonitorNumber: + self.screens.monitor_number = self.MonitorNumber + self.screens.set_current_display(self.MonitorNumber) + Receiver.send_message(u'screen_changed') diff --git a/openlp/core/ui/maindisplay.py b/openlp/core/ui/maindisplay.py index eaf1ed78f..5c2394ab2 100644 --- a/openlp/core/ui/maindisplay.py +++ b/openlp/core/ui/maindisplay.py @@ -130,13 +130,15 @@ class MainDisplay(DisplayWidget): QtCore.SIGNAL(u'media_pause'), self.onMediaPause) QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'media_stop'), self.onMediaStop) + QtCore.QObject.connect(Receiver.get_receiver(), + QtCore.SIGNAL(u'update_config'), self.setup) - def setup(self, screenNumber): + def setup(self): """ Sets up the screen on a particular screen. - @param (integer) screen This is the screen number. """ - log.debug(u'Setup %s for %s ' %(self.screens, screenNumber)) + log.debug(u'Setup %s for %s ' %(self.screens, + self.screens.monitor_number)) self.setVisible(False) self.screen = self.screens.current #Sort out screen locations and sizes @@ -183,7 +185,6 @@ class MainDisplay(DisplayWidget): else: self.setVisible(False) self.primary = True - Receiver.send_message(u'screen_changed') def resetDisplay(self): Receiver.send_message(u'stop_display_loop') @@ -247,7 +248,7 @@ class MainDisplay(DisplayWidget): else: self.display_text.setPixmap(QtGui.QPixmap.fromImage(frame)) self.display_frame = frame - if not self.isVisible(): + if not self.isVisible() and self.screens.display: self.setVisible(True) self.showFullScreen() else: @@ -320,4 +321,4 @@ class MainDisplay(DisplayWidget): self.video.setVisible(False) self.display_text.show() self.display_image.show() - self.blankDisplay(False, False) \ No newline at end of file + self.blankDisplay(False, False) diff --git a/openlp/core/ui/mainwindow.py b/openlp/core/ui/mainwindow.py index 13d880407..9a97715a0 100644 --- a/openlp/core/ui/mainwindow.py +++ b/openlp/core/ui/mainwindow.py @@ -190,19 +190,19 @@ class Ui_MainWindow(object): self.ThemeManagerDock.setVisible(self.settingsmanager.showThemeManager) # Create the menu items self.FileNewItem = QtGui.QAction(MainWindow) - self.FileNewItem.setIcon( - self.ServiceManagerContents.Toolbar.getIconFromTitle( - u'New Service')) + #self.FileNewItem.setIcon( + # self.ServiceManagerContents.Toolbar.getIconFromTitle( + # u'New Service')) self.FileNewItem.setObjectName(u'FileNewItem') self.FileOpenItem = QtGui.QAction(MainWindow) - self.FileOpenItem.setIcon( - self.ServiceManagerContents.Toolbar.getIconFromTitle( - u'Open Service')) + #self.FileOpenItem.setIcon( + # self.ServiceManagerContents.Toolbar.getIconFromTitle( + # u'Open Service')) self.FileOpenItem.setObjectName(u'FileOpenItem') self.FileSaveItem = QtGui.QAction(MainWindow) - self.FileSaveItem.setIcon( - self.ServiceManagerContents.Toolbar.getIconFromTitle( - u'Save Service')) + #self.FileSaveItem.setIcon( + # self.ServiceManagerContents.Toolbar.getIconFromTitle( + # u'Save Service')) self.FileSaveItem.setObjectName(u'FileSaveItem') self.FileSaveAsItem = QtGui.QAction(MainWindow) self.FileSaveAsItem.setObjectName(u'FileSaveAsItem') @@ -496,6 +496,8 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): QtCore.SIGNAL(u'version_check'), self.versionCheck) QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'blank_check'), self.blankCheck) + QtCore.QObject.connect(Receiver.get_receiver(), + QtCore.SIGNAL(u'screen_changed'), self.screenChanged) QtCore.QObject.connect(self.FileNewItem, QtCore.SIGNAL(u'triggered()'), self.ServiceManagerContents.onNewService) @@ -512,7 +514,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): #RenderManager needs to call ThemeManager and #ThemeManager needs to call RenderManager self.RenderManager = RenderManager(self.ThemeManagerContents, - self.screens, self.getMonitorNumber()) + self.screens) #Define the media Dock Manager self.mediaDockManager = MediaDockManager(self.MediaToolBox) log.info(u'Load Plugins') @@ -563,24 +565,13 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Ok), QtGui.QMessageBox.Ok) - def getMonitorNumber(self): - """ - Set up the default behaviour of the monitor configuration in - here. Currently it is set to default to monitor 0 if the saved - monitor number does not exist. - """ - screen_number = int(self.generalConfig.get_config(u'monitor', 0)) - if not self.screens.screen_exists(screen_number): - screen_number = 0 - return screen_number - def show(self): """ Show the main form, as well as the display form """ self.showMaximized() - screen_number = self.getMonitorNumber() - self.mainDisplay.setup(screen_number) + #screen_number = self.getMonitorNumber() + self.mainDisplay.setup() if self.mainDisplay.isVisible(): self.mainDisplay.setFocus() self.activateWindow() @@ -598,7 +589,6 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): QtGui.QMessageBox.Ok) def versionThread(self): - #app_version = self.applicationVersion[u'full'] vT = VersionThread(self, self.applicationVersion, self.generalConfig) vT.start() @@ -621,13 +611,10 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): Show the Settings dialog """ self.settingsForm.exec_() - updated_display = self.getMonitorNumber() - 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) - #Trigger after changes have been made - Receiver.send_message(u'config_updated') + + def screenChanged(self): + self.RenderManager.update_display() + self.mainDisplay.setup() self.activateWindow() def closeEvent(self, event): diff --git a/openlp/core/ui/screen.py b/openlp/core/ui/screen.py index baf7e0d5e..32cc5ba50 100644 --- a/openlp/core/ui/screen.py +++ b/openlp/core/ui/screen.py @@ -37,14 +37,17 @@ class ScreenList(object): self.preview = None self.current = None self.screen_list = [] - self.count = 0 + self.display_count = 0 + #actual display number self.current_display = 0 + #save config display number + self.monitor_number = 0 def add_screen(self, screen): if screen[u'primary']: self.current = screen self.screen_list.append(screen) - self.count += 1 + self.display_count += 1 def screen_exists(self, number): for screen in self.screen_list: @@ -53,21 +56,15 @@ class ScreenList(object): return False def set_current_display(self, number): - if number + 1 > self.count: + """ + Set up the current screen dimensions + """ + if number + 1 > self.display_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: + if self.display_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 diff --git a/openlp/core/ui/servicemanager.py b/openlp/core/ui/servicemanager.py index 4565a9527..d7acbdf4f 100644 --- a/openlp/core/ui/servicemanager.py +++ b/openlp/core/ui/servicemanager.py @@ -33,7 +33,7 @@ log = logging.getLogger(__name__) from PyQt4 import QtCore, QtGui from openlp.core.lib import PluginConfig, OpenLPToolbar, ServiceItem, \ - contextMenuAction, Receiver, str_to_bool, build_icon + contextMenuAction, Receiver, str_to_bool, build_icon, ItemCapabilities from openlp.core.ui import ServiceNoteForm, ServiceItemEditForm class ServiceManagerList(QtGui.QTreeWidget): @@ -233,9 +233,9 @@ class ServiceManager(QtGui.QWidget): self.editAction.setVisible(False) self.maintainAction.setVisible(False) self.notesAction.setVisible(False) - if serviceItem[u'service_item'].edit_enabled: + if serviceItem[u'service_item'].is_capable(ItemCapabilities.AllowsEdit): self.editAction.setVisible(True) - if serviceItem[u'service_item'].maintain_allowed: + if serviceItem[u'service_item'].is_capable(ItemCapabilities.AllowsMaintain): self.maintainAction.setVisible(True) if item.parent() is None: self.notesAction.setVisible(True) @@ -713,7 +713,7 @@ class ServiceManager(QtGui.QWidget): get_config(u'auto preview', u'False')): item += 1 if self.serviceItems and item < len(self.serviceItems) and \ - self.serviceItems[item][u'service_item'].auto_preview_allowed: + serviceItem[u'service_item'].is_capable(ItemCapabilities.AllowsPreview): self.parent.PreviewController.addServiceManagerItem( self.serviceItems[item][u'service_item'], 0) @@ -722,7 +722,8 @@ class ServiceManager(QtGui.QWidget): Posts a remote edit message to a plugin to allow item to be edited. """ item, count = self.findServiceItem() - if self.serviceItems[item][u'service_item'].edit_enabled: + if self.serviceItems[item][u'service_item'].\ + is_capable(ItemCapabilities.AllowsEdit): self.remoteEditTriggered = True Receiver.send_message(u'%s_edit' % self.serviceItems[item][u'service_item'].name, u'L:%s' % diff --git a/openlp/core/ui/settingsform.py b/openlp/core/ui/settingsform.py index 4d59b850f..c86525a54 100644 --- a/openlp/core/ui/settingsform.py +++ b/openlp/core/ui/settingsform.py @@ -34,11 +34,11 @@ log = logging.getLogger(__name__) class SettingsForm(QtGui.QDialog, Ui_SettingsDialog): - def __init__(self, screen_list, mainWindow, parent=None): + def __init__(self, screens, mainWindow, parent=None): QtGui.QDialog.__init__(self, parent) self.setupUi(self) # General tab - self.GeneralTab = GeneralTab(screen_list) + self.GeneralTab = GeneralTab(screens) self.addTab(u'General', self.GeneralTab) # Themes tab self.ThemesTab = ThemesTab(mainWindow) diff --git a/openlp/core/ui/slidecontroller.py b/openlp/core/ui/slidecontroller.py index c802219b5..35f520c9e 100644 --- a/openlp/core/ui/slidecontroller.py +++ b/openlp/core/ui/slidecontroller.py @@ -30,6 +30,8 @@ import os from PyQt4 import QtCore, QtGui from PyQt4.phonon import Phonon +from openlp.core.lib import ItemCapabilities + class HideMode(object): """ This is basically an enumeration class which specifies the mode of a Bible. @@ -375,8 +377,7 @@ class SlideController(QtGui.QWidget): self.Toolbar.makeWidgetsInvisible(self.image_list) if item.is_text(): self.Toolbar.makeWidgetsInvisible(self.image_list) - if item.is_song() and \ - str_to_bool(self.songsconfig.get_config(u'show songbar', True)) \ + if str_to_bool(self.songsconfig.get_config(u'show songbar', True)) \ and len(self.slideList) > 0: self.Toolbar.makeWidgetsVisible([u'Song Menu']) elif item.is_image(): @@ -395,7 +396,7 @@ class SlideController(QtGui.QWidget): self.Toolbar.setVisible(True) self.Mediabar.setVisible(False) self.Toolbar.makeWidgetsInvisible(self.song_edit_list) - if item.edit_enabled and item.from_plugin: + if item.is_capable(ItemCapabilities.AllowsEdit) and item.from_plugin: self.Toolbar.makeWidgetsVisible(self.song_edit_list) elif item.is_media(): self.Toolbar.setVisible(False) @@ -494,15 +495,18 @@ class SlideController(QtGui.QWidget): bits = frame[u'verseTag'].split(u':') 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:] ) - row = bits[1][0:] + if bits[0] == self.trUtf8('Verse') or \ + bits[0] == self.trUtf8('Chorus'): + tag = u'%s\n%s' % (bits[0][0], bits[1][0:] ) + tag1 = u'%s%s' % (bits[0][0], bits[1][0:] ) + row = tag else: tag = bits[0] + tag1 = tag row = bits[0][0:1] - if tag not in self.slideList: - self.slideList[tag] = framenumber - self.SongMenu.menu().addAction(self.trUtf8(u'%s'%tag), + if tag1 not in self.slideList: + self.slideList[tag1] = framenumber + self.SongMenu.menu().addAction(self.trUtf8(u'%s'%tag1), self.onSongBarHandler) else: row += 1 @@ -519,6 +523,7 @@ class SlideController(QtGui.QWidget): slide_height = width * self.parent.RenderManager.screen_ratio row += 1 rowitem.setText(unicode(row)) + rowitem.setTextAlignment(QtCore.Qt.AlignVCenter) self.PreviewListWidget.setItem(framenumber, 0, rowitem) self.PreviewListWidget.setItem(framenumber, 1, item) if slide_height != 0: @@ -759,7 +764,7 @@ class SlideController(QtGui.QWidget): else: self.mediaObject.stop() self.mediaObject.clearQueue() - file = os.path.join(item.service_item_path, item.get_frame_title()) + file = os.path.join(item.get_frame_path(), item.get_frame_title()) self.mediaObject.setCurrentSource(Phonon.MediaSource(file)) self.onMediaPlay() diff --git a/openlp/core/ui/test/test_service_manager.py b/openlp/core/ui/test/test_service_manager.py deleted file mode 100644 index 3755e459c..000000000 --- a/openlp/core/ui/test/test_service_manager.py +++ /dev/null @@ -1,160 +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, Christian Richter, 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 sys -import os -import os.path -import logging - -from PyQt4 import QtGui - -from openlp.core.ui import ServiceManager -from openlp.plugins.images.lib import ImageServiceItem - -mypath = os.path.split(os.path.abspath(__file__))[0] -sys.path.insert(0, (os.path.join(mypath, '..', '..', '..', '..'))) - -logging.basicConfig(filename='test_service_manager.log', level=logging.INFO, - filemode='w') - -# # from http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/66062 -# def whoami(depth=1): -# return sys._getframe(depth).f_code.co_name -global app -global log -log = logging.getLogger(u'TestServiceManager') - -class TestServiceManager_base: - def __init__(self): - pass - - def setup_class(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) - log.info(u'--------------- Setup Done -------------') - - def teardown_method(self, method): - 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)) - # make a selection of it - 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())) - - def test_easy(self): - log.info(u'test_easy') - item = ImageServiceItem(None) - item.add(u'test.gif') - self.s.addServiceItem(item) - answer = self.s.service_as_text() - log.info(u'Answer = ' + unicode(answer)) - lines = answer.split(u'\n') - log.info(u'lines = ' + unicode(lines)) - assert lines[0].startswith(u'# 1: return False service_item.title = unicode(self.trUtf8('Media')) + service_item.add_capability(ItemCapabilities.RequiresMedia) for item in items: bitem = self.ListView.item(item.row()) filename = unicode((bitem.data(QtCore.Qt.UserRole)).toString()) diff --git a/openlp/plugins/presentations/lib/mediaitem.py b/openlp/plugins/presentations/lib/mediaitem.py index 6e9bbfaed..1b4097b6c 100644 --- a/openlp/plugins/presentations/lib/mediaitem.py +++ b/openlp/plugins/presentations/lib/mediaitem.py @@ -152,7 +152,6 @@ class PresentationMediaItem(MediaManagerItem): service_item.title = unicode(self.DisplayTypeComboBox.currentText()) service_item.shortname = unicode(self.DisplayTypeComboBox.currentText()) shortname = service_item.shortname - for item in items: bitem = self.ListView.item(item.row()) filename = unicode((bitem.data(QtCore.Qt.UserRole)).toString()) diff --git a/openlp/plugins/red-x.png b/openlp/plugins/red-x.png deleted file mode 100644 index c23f2ac9f..000000000 Binary files a/openlp/plugins/red-x.png and /dev/null differ diff --git a/openlp/plugins/songs/forms/editsongform.py b/openlp/plugins/songs/forms/editsongform.py index a369e46a1..b2b1b14c4 100644 --- a/openlp/plugins/songs/forms/editsongform.py +++ b/openlp/plugins/songs/forms/editsongform.py @@ -411,16 +411,18 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog): self.SongTabWidget.setCurrentIndex(2) self.AuthorsListView.setFocus() #split the verse list by space and mark lower case for testing - taglist = unicode(self.trUtf8(' bcitped')) + taglist = unicode(self.trUtf8(' bitped')) for verse in unicode(self.VerseOrderEdit.text()).lower().split(u' '): if len(verse) > 1: - if verse[0:1] == u'%s' % self.trUtf8('v') and verse[1:].isdigit(): + if (verse[0:1] == u'%s' % self.trUtf8('v') or + verse[0:1] == u'%s' % self.trUtf8('c')) \ + and verse[1:].isdigit(): pass else: self.SongTabWidget.setCurrentIndex(0) self.VerseOrderEdit.setFocus() return False, \ - self.trUtf8('Invalid verse entry - vX') + self.trUtf8('Invalid verse entry - Vx or Cx') else: if taglist.find(verse) > -1: pass @@ -429,7 +431,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog): self.VerseOrderEdit.setFocus() return False, \ self.trUtf8(\ - 'Invalid verse entry - values must be Numeric, I,B,C,T,P,E,O') + 'Invalid verse entry, values must be I,B,T,P,E,O,Vx,Cx') return True, u'' def onTitleEditItemLostFocus(self): diff --git a/openlp/plugins/songs/forms/editverseform.py b/openlp/plugins/songs/forms/editverseform.py index 2666c146e..326946bc4 100644 --- a/openlp/plugins/songs/forms/editverseform.py +++ b/openlp/plugins/songs/forms/editverseform.py @@ -59,46 +59,43 @@ class EditVerseForm(QtGui.QDialog, Ui_EditVerseDialog): def onAddIntro(self): self.startNewLine() - self.VerseTextEdit.insertPlainText(u'---[%s:1]---\n' - % self.trUtf8('Intro')) + self.VerseTextEdit.insertPlainText(u'---[Intro:1]---\n') self.VerseTextEdit.setFocus() def onAddEnding(self): self.startNewLine() - self.VerseTextEdit.insertPlainText(u'---[%s:1]---\n' - % self.trUtf8('Ending')) + self.VerseTextEdit.insertPlainText(u'---[Ending:1]---\n') self.VerseTextEdit.setFocus() def onAddOther(self): self.startNewLine() - self.VerseTextEdit.insertPlainText(u'---[%s:1]---\n' - % self.trUtf8('Other')) + self.VerseTextEdit.insertPlainText(u'---[Other:1]---\n') self.VerseTextEdit.setFocus() def onAddPreChorus(self): self.startNewLine() - self.VerseTextEdit.insertPlainText(u'---[%s:1]---\n' - % self.trUtf8('Pre-Chorus')) + self.VerseTextEdit.insertPlainText(u'---[Pre-Chorus:1]---\n') self.VerseTextEdit.setFocus() def onAddBridge(self): self.startNewLine() - self.VerseTextEdit.insertPlainText(u'---[%s:1]---\n' - % self.trUtf8('Bridge')) + self.VerseTextEdit.insertPlainText(u'---[Bridge:1]---\n') self.VerseTextEdit.setFocus() def onAddChorus(self): self.startNewLine() - self.VerseTextEdit.insertPlainText(u'---[%s:1]---\n' - % self.trUtf8('Chorus')) + count = self.VerseTextEdit.toPlainText().\ + count(u'---[Chorus') + self.VerseTextEdit.insertPlainText(u'---[Chorus:%s]---\n' + % unicode(count + 1)) self.VerseTextEdit.setFocus() def onAddVerse(self): self.startNewLine() count = self.VerseTextEdit.toPlainText().\ - count(u'---[%s' % self.trUtf8('Verse')) - self.VerseTextEdit.insertPlainText(u'---[%s:%s]---\n' - % (self.trUtf8('Verse'), count + 1)) + count(u'---[Verse') + self.VerseTextEdit.insertPlainText(u'---[Verse:%s]---\n' + % unicode(count + 1)) self.VerseTextEdit.setFocus() def setVerse(self, text, verseCount=0, single=False, tag=u'Verse:1'): @@ -155,7 +152,8 @@ class EditVerseForm(QtGui.QDialog, Ui_EditVerseDialog): return text def onVerseComboChanged(self, id): - if unicode(self.VerseListComboBox.currentText()) == self.trUtf8('Verse'): + if unicode(self.VerseListComboBox.currentText()) == self.trUtf8('Verse') or \ + unicode(self.VerseListComboBox.currentText()) == self.trUtf8('Chrous'): self.SubVerseListComboBox.setEnabled(True) else: self.SubVerseListComboBox.setEnabled(False) diff --git a/openlp/plugins/songs/lib/__init__.py b/openlp/plugins/songs/lib/__init__.py index 338a88b91..4ed56d06b 100644 --- a/openlp/plugins/songs/lib/__init__.py +++ b/openlp/plugins/songs/lib/__init__.py @@ -26,3 +26,5 @@ from manager import SongManager from songstab import SongsTab from mediaitem import SongMediaItem +from sofimport import SofImport +from songimport import SongImport diff --git a/openlp/plugins/songs/lib/manager.py b/openlp/plugins/songs/lib/manager.py index 87f0e6132..dcb49bfcd 100644 --- a/openlp/plugins/songs/lib/manager.py +++ b/openlp/plugins/songs/lib/manager.py @@ -133,6 +133,12 @@ class SongManager(): """ return self.session.query(Author).get(id) + def get_author_by_name(self, name): + """ + Get author by display name + """ + return self.session.query(Author).filter_by(display_name=name).first() + def save_author(self, author): """ Save the Author and refresh the cache @@ -172,6 +178,12 @@ class SongManager(): """ return self.session.query(Topic).get(id) + def get_topic_by_name(self, name): + """ + Get topic by name + """ + return self.session.query(Topic).filter_by(name=name).first() + def save_topic(self, topic): """ Save the Topic @@ -211,6 +223,12 @@ class SongManager(): """ return self.session.query(Book).get(id) + def get_book_by_name(self, name): + """ + Get book by name + """ + return self.session.query(Book).filter_by(name=name).first() + def save_book(self, book): """ Save the Book diff --git a/openlp/plugins/songs/lib/mediaitem.py b/openlp/plugins/songs/lib/mediaitem.py index 9ac8ec977..e2b1dbf80 100644 --- a/openlp/plugins/songs/lib/mediaitem.py +++ b/openlp/plugins/songs/lib/mediaitem.py @@ -28,7 +28,7 @@ import logging from PyQt4 import QtCore, QtGui from openlp.core.lib import MediaManagerItem, SongXMLParser, \ - BaseListWithDnD, Receiver, str_to_bool + BaseListWithDnD, Receiver, str_to_bool, ItemCapabilities from openlp.plugins.songs.forms import EditSongForm, SongMaintenanceForm log = logging.getLogger(__name__) @@ -271,12 +271,23 @@ class SongMediaItem(MediaManagerItem): self.edit_song_form.exec_() def onDeleteClick(self): - item = self.ListView.currentItem() - if item: - item_id = (item.data(QtCore.Qt.UserRole)).toInt()[0] - self.parent.songmanager.delete_song(item_id) - row = self.ListView.row(item) - self.ListView.takeItem(row) + items = self.ListView.selectedIndexes() + if items: + if len(items) == 1: + del_message = self.trUtf8('Delete song?') + else: + del_message = unicode(self.trUtf8('Delete %d song?')) % len(items) + ans = QtGui.QMessageBox.question(self, + self.trUtf8('Delete Confirmation'), del_message, + QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Ok| + QtGui.QMessageBox.Cancel), + QtGui.QMessageBox.Ok) + if ans == QtGui.QMessageBox.Cancel: + return + for item in items: + item_id = (item.data(QtCore.Qt.UserRole)).toInt()[0] + self.parent.songmanager.delete_song(item_id) + self.onSearchTextButtonClick() def generateSlideData(self, service_item): raw_footer = [] @@ -290,10 +301,10 @@ class SongMediaItem(MediaManagerItem): item_id = (item.data(QtCore.Qt.UserRole)).toInt()[0] else: item_id = self.remoteSong - service_item.auto_preview_allowed = True + service_item.add_capability(ItemCapabilities.AllowsEdit) + service_item.add_capability(ItemCapabilities.AllowsPreview) song = self.parent.songmanager.get_song(item_id) service_item.theme = song.theme_name - service_item.edit_enabled = True service_item.editId = item_id if song.lyrics.startswith(u' 2: + self.new_song() + + def process_paragraph_line(self, text): + """ + Process a single line. Throw away that text which isn't relevant, i.e. + stuff that appears at the end of the song. + Anything that is OK, append to the current verse + """ + text = text.strip() + if text == u'': + self.blanklines += 1 + if self.blanklines > 1: + return + if self.song.get_title() != u'': + self.finish_verse() + return + self.blanklines = 0 + if self.skip_to_close_bracket: + if text.endswith(u')'): + self.skip_to_close_bracket = False + return + if text.startswith(u'CCL Licence'): + self.italics = False + return + if text == u'A Songs of Fellowship Worship Resource': + return + if text.startswith(u'(NB.') or text.startswith(u'(Regrettably') \ + or text.startswith(u'(From'): + self.skip_to_close_bracket = True + return + if text.startswith(u'Copyright'): + self.song.add_copyright(text) + return + if text == u'(Repeat)': + self.finish_verse() + self.song.repeat_verse() + return + if self.song.get_title() == u'': + if self.song.get_copyright() == u'': + self.add_author(text) + else: + self.song.add_copyright(text) + return + self.add_verse_line(text) + + def process_textportion(self, textportion): + """ + Process a text portion. Here we just get the text and detect if + it's bold or italics. If it's bold then its a song number or song title. + Song titles are in all capitals, so we must bring the capitalization + into line + """ + text = textportion.getString() + text = self.tidy_text(text) + if text.strip() == u'': + return text + if textportion.CharWeight == BOLD: + boldtext = text.strip() + if boldtext.isdigit() and self.song.get_song_number() == '': + self.add_songnumber(boldtext) + return u'' + if self.song.get_title() == u'': + text = self.uncap_text(text) + self.add_title(text) + return text + if text.strip().startswith(u'('): + return text + self.italics = (textportion.CharPosture == ITALIC) + return text + + def new_song(self): + """ + A change of song. Store the old, create a new + ... but only if the last song was complete. If not, stick with it + """ + if self.song: + self.finish_verse() + if not self.song.check_complete(): + return + self.song.finish() + self.song = SongImport(self.manager) + self.skip_to_close_bracket = False + self.is_chorus = False + self.italics = False + self.currentverse = u'' + + def add_songnumber(self, song_no): + """ + Add a song number, store as alternate title. Also use the song + number to work out which songbook we're in + """ + self.song.set_song_number(song_no) + self.song.set_alternate_title(song_no + u'.') + if int(song_no) <= 640: + self.song.set_song_book(u'Songs of Fellowship 1', + u'Kingsway Publications') + elif int(song_no) <= 1150: + self.song.set_song_book(u'Songs of Fellowship 2', + u'Kingsway Publications') + elif int(song_no) <= 1690: + self.song.set_song_book(u'Songs of Fellowship 3', + u'Kingsway Publications') + else: + self.song.set_song_book(u'Songs of Fellowship 4', + u'Kingsway Publications') + + def add_title(self, text): + """ + Add the title to the song. Strip some leading/trailing punctuation that + we don't want in a title + """ + title = text.strip() + if title.startswith(u'\''): + title = title[1:] + if title.endswith(u','): + title = title[:-1] + self.song.set_title(title) + + def add_author(self, text): + """ + Add the author. OpenLP stores them individually so split by 'and', '&' + and comma. + However need to check for "Mr and Mrs Smith" and turn it to + "Mr Smith" and "Mrs Smith". + """ + text = text.replace(u' and ', u' & ') + for author in text.split(u','): + authors = author.split(u'&') + for i in range(len(authors)): + author2 = authors[i].strip() + if author2.find(u' ') == -1 and i < len(authors) - 1: + author2 = author2 + u' ' \ + + authors[i + 1].strip().split(u' ')[-1] + if author2.endswith(u'.'): + author2 = author2[:-1] + if author2: + self.song.add_author(author2) + + def add_verse_line(self, text): + """ + Add a line to the current verse. If the formatting has changed and + we're beyond the second line of first verse, then this indicates + a change of verse. Italics are a chorus + """ + if self.italics != self.is_chorus and ((len(self.song.verses) > 0) or + (self.currentverse.count(u'\n') > 1)): + self.finish_verse() + if self.italics: + self.is_chorus = True + self.currentverse += text + u'\n' + + def finish_verse(self): + """ + Verse is finished, store it. Note in book 1+2, some songs are formatted + incorrectly. Here we try and split songs with missing line breaks into + the correct number of verses. + """ + if self.currentverse.strip() == u'': + return + if self.is_chorus: + versetag = u'C' + splitat = None + else: + versetag = u'V' + splitat = self.verse_splits(self.song.get_song_number()) + if splitat: + ln = 0 + verse = u'' + for line in self.currentverse.split(u'\n'): + ln += 1 + if line == u'' or ln > splitat: + self.song.add_verse(verse, versetag) + ln = 0 + if line: + verse = line + u'\n' + else: + verse = u'' + else: + verse += line + u'\n' + if verse: + self.song.add_verse(verse, versetag) + else: + self.song.add_verse(self.currentverse, versetag) + self.currentverse = u'' + self.is_chorus = False + + def tidy_text(self, text): + """ + Get rid of some dodgy unicode and formatting characters we're not + interested in. Some can be converted to ascii. + """ + text = text.replace(u'\t', u' ') + text = text.replace(u'\r', u'\n') + text = text.replace(u'\u2018', u'\'') + text = text.replace(u'\u2019', u'\'') + text = text.replace(u'\u201c', u'"') + text = text.replace(u'\u201d', u'"') + text = text.replace(u'\u2026', u'...') + text = text.replace(u'\u2013', u'-') + text = text.replace(u'\u2014', u'-') + return text + + def uncap_text(self, text): + """ + Words in the title are in all capitals, so we lowercase them. + However some of these words, e.g. referring to God need a leading + capital letter. + + There is a complicated word "One", which is sometimes lower and + sometimes upper depending on context. Never mind, keep it lower. + """ + textarr = re.split(u'(\W+)', text) + textarr[0] = textarr[0].capitalize() + for i in range(1, len(textarr)): + # Do not translate these. Fixed strings in SOF song file + if textarr[i] in (u'JESUS', u'CHRIST', u'KING', u'ALMIGHTY', + u'REDEEMER', u'SHEPHERD', u'SON', u'GOD', u'LORD', u'FATHER', + u'HOLY', u'SPIRIT', u'LAMB', u'YOU', u'YOUR', u'I', u'I\'VE', + u'I\'M', u'I\'LL', u'SAVIOUR', u'O', u'YOU\'RE', u'HE', u'HIS', + u'HIM', u'ZION', u'EMMANUEL', u'MAJESTY', u'JESUS\'', u'JIREH', + u'JUDAH', u'LION', u'LORD\'S', u'ABRAHAM', u'GOD\'S', + u'FATHER\'S', u'ELIJAH'): + textarr[i] = textarr[i].capitalize() + else: + textarr[i] = textarr[i].lower() + text = u''.join(textarr) + return text + + def verse_splits(self, song_number): + """ + Because someone at Kingsway forgot to check the 1+2 RTF file, + some verses were not formatted correctly. + """ + if song_number == 11: return 8 + if song_number == 18: return 5 + if song_number == 21: return 6 + if song_number == 23: return 4 + if song_number == 24: return 7 + if song_number == 27: return 4 + if song_number == 31: return 6 + if song_number == 49: return 4 + if song_number == 50: return 8 + if song_number == 70: return 4 + if song_number == 75: return 8 + if song_number == 79: return 6 + if song_number == 97: return 7 + if song_number == 107: return 4 + if song_number == 109: return 4 + if song_number == 133: return 4 + if song_number == 155: return 10 + if song_number == 156: return 8 + if song_number == 171: return 4 + if song_number == 188: return 7 + if song_number == 192: return 4 + if song_number == 208: return 8 + if song_number == 215: return 8 + if song_number == 220: return 4 + if song_number == 247: return 6 + if song_number == 248: return 6 + if song_number == 251: return 8 + if song_number == 295: return 8 + if song_number == 307: return 5 + if song_number == 314: return 6 + if song_number == 325: return 8 + if song_number == 386: return 6 + if song_number == 415: return 4 + if song_number == 426: return 4 + if song_number == 434: return 5 + if song_number == 437: return 4 + if song_number == 438: return 6 + if song_number == 456: return 8 + if song_number == 461: return 4 + if song_number == 469: return 4 + if song_number == 470: return 5 + if song_number == 476: return 6 + if song_number == 477: return 7 + if song_number == 480: return 8 + if song_number == 482: return 4 + if song_number == 512: return 4 + if song_number == 513: return 8 + if song_number == 518: return 5 + if song_number == 520: return 4 + if song_number == 523: return 6 + if song_number == 526: return 8 + if song_number == 527: return 4 + if song_number == 529: return 4 + if song_number == 537: return 4 + if song_number == 555: return 6 + if song_number == 581: return 4 + if song_number == 589: return 6 + if song_number == 590: return 4 + if song_number == 593: return 8 + if song_number == 596: return 4 + if song_number == 610: return 6 + if song_number == 611: return 6 + if song_number == 619: return 8 + if song_number == 645: return 5 + if song_number == 653: return 6 + if song_number == 683: return 7 + if song_number == 686: return 4 + if song_number == 697: return 8 + if song_number == 698: return 4 + if song_number == 704: return 6 + if song_number == 716: return 4 + if song_number == 717: return 6 + if song_number == 730: return 4 + if song_number == 731: return 8 + if song_number == 732: return 8 + if song_number == 738: return 4 + if song_number == 756: return 9 + if song_number == 815: return 6 + if song_number == 830: return 8 + if song_number == 831: return 4 + if song_number == 876: return 6 + if song_number == 877: return 6 + if song_number == 892: return 4 + if song_number == 894: return 6 + if song_number == 902: return 8 + if song_number == 905: return 8 + if song_number == 921: return 6 + if song_number == 940: return 7 + if song_number == 955: return 9 + if song_number == 968: return 8 + if song_number == 972: return 7 + if song_number == 974: return 4 + if song_number == 988: return 6 + if song_number == 991: return 5 + if song_number == 1002: return 8 + if song_number == 1024: return 8 + if song_number == 1044: return 9 + if song_number == 1088: return 6 + if song_number == 1117: return 6 + if song_number == 1119: return 7 + return None + diff --git a/openlp/plugins/songs/lib/songimport.py b/openlp/plugins/songs/lib/songimport.py new file mode 100644 index 000000000..6adfcad7f --- /dev/null +++ b/openlp/plugins/songs/lib/songimport.py @@ -0,0 +1,273 @@ +# -*- 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, Christian Richter, 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 string +from openlp.core.lib import SongXMLBuilder +from openlp.plugins.songs.lib.models import Song, Author, Topic, Book + +class SongImport(object): + """ + Helper class for import a song from a third party source into OpenLP + + This class just takes the raw strings, and will work out for itself + whether the authors etc already exist and add them or refer to them + as necessary + """ + + def __init__(self, song_manager): + """ + Initialise and create defaults for properties + + song_manager is an instance of a SongManager, through which all + database access is performed + """ + self.manager = song_manager + self.title = u'' + self.song_number = u'' + self.alternate_title = u'' + self.copyright = u'' + self.comment = u'' + self.theme_name = u'' + self.ccli_number = u'' + self.authors = [] + self.topics = [] + self.song_book_name = u'' + self.song_book_pub = u'' + self.verse_order_list = [] + self.verses = [] + self.versecount = 0 + self.choruscount = 0 + + def get_title(self): + """ + Return the title + """ + return self.title + + def get_copyright(self): + """ + Return the copyright + """ + return self.copyright + + def get_song_number(self): + """ + Return the song number + """ + return self.song_number + + def set_title(self, title): + """ + Set the title + """ + self.title = title + + def set_alternate_title(self, title): + """ + Set the alternate title + """ + self.alternate_title = title + + def set_song_number(self, song_number): + """ + Set the song number + """ + self.song_number = song_number + + def set_song_book(self, song_book, publisher): + """ + Set the song book name and publisher + """ + self.song_book_name = song_book + self.song_book_pub = publisher + + def add_copyright(self, copyright): + """ + Build the copyright field + """ + if self.copyright != u'': + self.copyright += ' ' + self.copyright += copyright + + def add_author(self, text): + """ + Add an author to the list + """ + self.authors.append(text) + + def add_verse(self, verse, versetag): + """ + Add a verse. This is the whole verse, lines split by \n + Verse tag can be V1/C1/B etc, or 'V' and 'C' (will count the verses/ + choruses itself) or None, where it will assume verse + It will also attempt to detect duplicates. In this case it will just + add to the verse order + """ + for (oldversetag, oldverse) in self.verses: + if oldverse.strip() == verse.strip(): + self.verse_order_list.append(oldversetag) + return + if versetag.startswith(u'C'): + self.choruscount += 1 + if versetag == u'C': + versetag += unicode(self.choruscount) + if versetag == u'V' or not versetag: + self.versecount += 1 + versetag = u'V' + unicode(self.versecount) + self.verses.append([versetag, verse.rstrip()]) + self.verse_order_list.append(versetag) + if versetag.startswith(u'V') and self.contains_verse(u'C1'): + self.verse_order_list.append(u'C1') + + def repeat_verse(self): + """ + Repeat the previous verse in the verse order + """ + self.verse_order_list.append(self.verse_order_list[-1]) + + def contains_verse(self, versetag): + return versetag in self.verse_order_list + + def check_complete(self): + """ + Check the mandatory fields are entered (i.e. title and a verse) + Author not checked here, if no author then "Author unknown" is + automatically added + """ + if self.title == u'' or len(self.verses) == 0: + return False + else: + return True + + def remove_punctuation(self, text): + """ + Remove punctuation from the string for searchable fields + """ + for c in string.punctuation: + text = text.replace(c, u'') + return text + + def finish(self): + """ + All fields have been set to this song. Write it away + """ + if len(self.authors) == 0: + self.authors.append(u'Author unknown') + self.commit_song() + #self.print_song() + + def commit_song(self): + """ + Write the song and it's fields to disk + """ + song = Song() + song.title = self.title + song.search_title = self.remove_punctuation(self.title) \ + + '@' + self.alternate_title + song.song_number = self.song_number + song.search_lyrics = u'' + sxml = SongXMLBuilder() + sxml.new_document() + sxml.add_lyrics_to_song() + for (versetag, versetext) in self.verses: + if versetag[0] == u'C': + versetype = u'Chorus' + elif versetag[0] == u'V': + versetype = u'Verse' + elif versetag[0] == u'B': + versetype = u'Bridge' + elif versetag[0] == u'I': + versetype = u'Intro' + elif versetag[0] == u'P': + versetype = u'Prechorus' + elif versetag[0] == u'E': + versetype = u'Ending' + else: + versetype = u'Other' + sxml.add_verse_to_lyrics(versetype, versetag[1:], versetext) + song.search_lyrics += u' ' + self.remove_punctuation(versetext) + song.lyrics = unicode(sxml.extract_xml(), u'utf-8') + song.verse_order = u' '.join(self.verse_order_list) + song.copyright = self.copyright + song.comment = self.comment + song.theme_name = self.theme_name + song.ccli_number = self.ccli_number + for authortext in self.authors: + author = self.manager.get_author_by_name(authortext) + if author is None: + author = Author() + author.display_name = authortext + author.last_name = authortext.split(u' ')[-1] + author.first_name = u' '.join(authortext.split(u' ')[:-1]) + self.manager.save_author(author) + song.authors.append(author) + if self.song_book_name: + song_book = self.manager.get_book_by_name(self.song_book_name) + if song_book is None: + song_book = Book() + song_book.name = self.song_book_name + song_book.publisher = self.song_book_pub + self.manager.save_book(song_book) + song.song_book_id = song_book.id + for topictext in self.topics: + topic = self.manager.get_topic_by_name(topictext) + if topic is None: + topic = Topic() + topic.name = topictext + self.manager.save_topic(topic) + song.topics.append(topictext) + self.manager.save_song(song) + + def print_song(self): + """ + For debugging + """ + print u'========================================' \ + + u'========================================' + print u'TITLE: ' + self.title + print u'ALT TITLE: ' + self.alternate_title + for (versetag, versetext) in self.verses: + print u'VERSE ' + versetag + u': ' + versetext + print u'ORDER: ' + u' '.join(self.verse_order_list) + for author in self.authors: + print u'AUTHOR: ' + author + if self.copyright: + print u'COPYRIGHT: ' + self.copyright + if self.song_book_name: + print u'BOOK: ' + self.song_book_name + if self.song_book_pub: + print u'BOOK PUBLISHER: ' + self.song_book_pub + if self.song_number: + print u'NUMBER: ' + self.song_number + for topictext in self.topics: + print u'TOPIC: ' + topictext + if self.comment: + print u'COMMENT: ' + self.comment + if self.theme_name: + print u'THEME: ' + self.theme_name + if self.ccli_number: + print u'CCLI: ' + self.ccli_number + + diff --git a/openlp/plugins/songs/songsplugin.py b/openlp/plugins/songs/songsplugin.py index 152392443..2155e3c16 100644 --- a/openlp/plugins/songs/songsplugin.py +++ b/openlp/plugins/songs/songsplugin.py @@ -27,8 +27,9 @@ import logging from PyQt4 import QtCore, QtGui -from openlp.core.lib import Plugin, build_icon, PluginStatus -from openlp.plugins.songs.lib import SongManager, SongMediaItem, SongsTab +from openlp.core.lib import Plugin, build_icon, PluginStatus, Receiver +from openlp.plugins.songs.lib import SongManager, SongMediaItem, SongsTab, \ + SofImport from openlp.plugins.songs.forms import OpenLPImportForm, OpenSongExportForm, \ OpenSongImportForm, OpenLPExportForm @@ -102,24 +103,35 @@ class SongsPlugin(Plugin): self.ImportOpenlp1Item.setObjectName(u'ImportOpenlp1Item') self.ImportOpenlp2Item = QtGui.QAction(import_menu) self.ImportOpenlp2Item.setObjectName(u'ImportOpenlp2Item') + self.ImportSofItem = QtGui.QAction(import_menu) + self.ImportSofItem.setObjectName(u'ImportSofItem') # Add to menus self.ImportSongMenu.addAction(self.ImportOpenlp1Item) self.ImportSongMenu.addAction(self.ImportOpenlp2Item) self.ImportSongMenu.addAction(self.ImportOpenSongItem) + self.ImportSongMenu.addAction(self.ImportSofItem) import_menu.addAction(self.ImportSongMenu.menuAction()) # Translations... self.ImportSongMenu.setTitle(import_menu.trUtf8('&Song')) self.ImportOpenSongItem.setText(import_menu.trUtf8('OpenSong')) self.ImportOpenlp1Item.setText(import_menu.trUtf8('openlp.org 1.0')) self.ImportOpenlp1Item.setToolTip( - import_menu.trUtf8('Export songs in openlp.org 1.0 format')) + import_menu.trUtf8('Import songs in openlp.org 1.0 format')) self.ImportOpenlp1Item.setStatusTip( - import_menu.trUtf8('Export songs in openlp.org 1.0 format')) + import_menu.trUtf8('Import songs in openlp.org 1.0 format')) self.ImportOpenlp2Item.setText(import_menu.trUtf8('OpenLP 2.0')) self.ImportOpenlp2Item.setToolTip( - import_menu.trUtf8('Export songs in OpenLP 2.0 format')) + import_menu.trUtf8('Import songs in OpenLP 2.0 format')) self.ImportOpenlp2Item.setStatusTip( - import_menu.trUtf8('Export songs in OpenLP 2.0 format')) + import_menu.trUtf8('Import songs in OpenLP 2.0 format')) + self.ImportSofItem.setText( + import_menu.trUtf8('Songs of Fellowship')) + self.ImportSofItem.setToolTip( + import_menu.trUtf8('Import songs from the VOLS1_2.RTF, sof3words' \ + + '.rtf and sof4words.rtf supplied with the music books')) + self.ImportSofItem.setStatusTip( + import_menu.trUtf8('Import songs from the VOLS1_2.RTF, sof3words' \ + + '.rtf and sof4words.rtf supplied with the music books')) # Signals and slots QtCore.QObject.connect(self.ImportOpenlp1Item, QtCore.SIGNAL(u'triggered()'), self.onImportOpenlp1ItemClick) @@ -127,6 +139,8 @@ class SongsPlugin(Plugin): QtCore.SIGNAL(u'triggered()'), self.onImportOpenlp1ItemClick) QtCore.QObject.connect(self.ImportOpenSongItem, QtCore.SIGNAL(u'triggered()'), self.onImportOpenSongItemClick) + QtCore.QObject.connect(self.ImportSofItem, + QtCore.SIGNAL(u'triggered()'), self.onImportSofItemClick) self.ImportSongMenu.menuAction().setVisible(False) def add_export_menu_item(self, export_menu): @@ -169,6 +183,25 @@ class SongsPlugin(Plugin): def onImportOpenSongItemClick(self): self.opensong_import_form.show() + def onImportSofItemClick(self): + filename = QtGui.QFileDialog.getOpenFileName( + None, self.trUtf8('Open Songs of Fellowship file'), + u'', u'Songs of Fellowship file (*.rtf *.RTF)') + try: + sofimport = SofImport(self.songmanager) + sofimport.import_sof(unicode(filename)) + except: + log.exception('Could not import SoF file') + QtGui.QMessageBox.critical(None, + self.ImportSongMenu.trUtf8('Import Error'), + self.ImportSongMenu.trUtf8('Error importing Songs of ' + + 'Fellowship file.\nOpenOffice.org must be installed' + + ' and you must be using an unedited copy of the RTF' + + ' included with the Songs of Fellowship Music Editions'), + QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Ok), + QtGui.QMessageBox.Ok) + Receiver.send_message(u'load_song_list') + def onExportOpenlp1ItemClicked(self): self.openlp_export_form.show() diff --git a/openlp/plugins/songs/test/data_openlp1/amazing.olp b/openlp/plugins/songs/test/data_openlp1/amazing.olp deleted file mode 100644 index ef65237bc..000000000 Binary files a/openlp/plugins/songs/test/data_openlp1/amazing.olp and /dev/null differ diff --git a/openlp/plugins/songs/test/data_openlp1/sample3.olp b/openlp/plugins/songs/test/data_openlp1/sample3.olp deleted file mode 100644 index f29419894..000000000 Binary files a/openlp/plugins/songs/test/data_openlp1/sample3.olp and /dev/null differ diff --git a/openlp/plugins/songs/test/data_opensong/Amazing Grace b/openlp/plugins/songs/test/data_opensong/Amazing Grace deleted file mode 100644 index 06f3edd92..000000000 --- a/openlp/plugins/songs/test/data_opensong/Amazing Grace +++ /dev/null @@ -1,38 +0,0 @@ - - - Amazing Grace - John Newton - 1982 Jubilate Hymns Limited - - - - - 1037882 - God: Attributes - - - - - [V1] -. D D7 G D Bm E A A7 - Amazing grace how sweet the sound that saved a wretch like me; -. D D7 G D Bm A G D - I once was lost but now I'm found, was blind but now I see. - -[V2] -. D D7 G D Bm E A A7 - Twas grace that taught my heart to fear, and grace my fears relieved; -. D D7 G D Bm A G D - How precious did that grace appear the hour I first believed! - -[V3] -. D D7 G D Bm E A A7 - Through many dangers, toils, and snares I have already come; -. D D7 G D Bm A G D - 'Tis grace that brought me safe thus far and grace will lead me home. - -[V4] -. D D7 G D Bm E A A7 - When we've been there ten thousand years bright shining as the sun; -. D D7 G D Bm A G D - We've no less days to sing God's praise than when we'd first begun! \ No newline at end of file diff --git a/openlp/plugins/songs/test/data_opensong/PÃ¥ en fjern ensom høj b/openlp/plugins/songs/test/data_opensong/PÃ¥ en fjern ensom høj deleted file mode 100644 index 6023414ca..000000000 --- a/openlp/plugins/songs/test/data_opensong/PÃ¥ en fjern ensom høj +++ /dev/null @@ -1,56 +0,0 @@ -PÃ¥ en fjern ensom høj[V1] - PÃ¥ en fjern ensom høj, - Jesu kors dyrest stod, - symbolet pÃ¥ smerte og skam. - O, jeg elsker det kors, - hvor Guds søn gjorde bod, - da forbandelsen blev lagt pÃ¥ ham. - -[C1] - Jeg vil elske det urgamle kors, - i det kraft er der sejer og sang. - Lad mig favne det hellige kors, - det med kronen ombyttes engang. - -[V2] - O, det urgamle kors, - med sin hvile og fred, - tilhyllet i verdens foragt. - Se, det hellige lam, - som pÃ¥ Golgatha stred, - og til jorden Guds nÃ¥de har bragt. - -[C2] - Jeg vil elske det urgamle kors, - i det kraft er der sejer og sang. - Lad mig favne det hellige kors, - det med kronen ombyttes engang. - -[V3] - I det urgamle kors, - i hans blod farvet rødt, - en underfuld skønhed jeg ser. - Ja, det var pÃ¥ det kors, - at han selv blev forstødt, - nu skal aldrig for dommen jeg mer. - -[C3] - Jeg vil elske det urgamle kors, - i det kraft er der sejer og sang. - Lad mig favne det hellige kors, - det med kronen ombyttes engang. - -[V4] - For det urgamle kors, - stÃ¥r mit hjerte i brand, - min plads jeg nu har ved dets fod. - Til han kalder en dag, - mig til himmelens land, - og til hvilen hos Faderen god. - -[C4] - Jeg vil elske det urgamle kors, - i det kraft er der sejer og sang. - Lad mig favne det hellige kors, - det med kronen ombyttes engang. -V1 C1 V2 C2 V3 C3 V4 C4 \ No newline at end of file diff --git a/openlp/plugins/songs/test/data_opensong/The Solid Rock b/openlp/plugins/songs/test/data_opensong/The Solid Rock deleted file mode 100644 index bb1eecc97..000000000 --- a/openlp/plugins/songs/test/data_opensong/The Solid Rock +++ /dev/null @@ -1,28 +0,0 @@ - - - The Solid Rock - Edward Mote and John B. Dykes - Public Domain - V1 C V2 C V3 C V4 C - 101740 - Christ: Victory - Fruit: Peace/Comfort - [V] -. E B A B E -1My hope is built on nothing less than Jesus' blood and righteousness; -2When darkness veils His lovely face, I rest on His un___changing grace. -3His oath, His cove_____nant, His blood|support me in the whelming flood; -4When He shall come with trumpet sound, O may I then in Him be found; -. E B A B E -1I dare not trust the sweetest frame, but wholly lean on Jesus' name. -2In every high and stormy gale, my anchor holds within the veil. -3When all around my soul gives way, He then is all my hope and stay. -4Dressed in His righteous___ness alone, fault___less to stand be_fore the throne. - -[C] -. E A - On Christ, the solid rock I stand; -. E B - All other ground is sinking sand, -. A B E - All other ground is sinking sand. \ No newline at end of file diff --git a/openlp/plugins/songs/test/data_text/CCLI example.txt b/openlp/plugins/songs/test/data_text/CCLI example.txt deleted file mode 100644 index 6a5c23222..000000000 --- a/openlp/plugins/songs/test/data_text/CCLI example.txt +++ /dev/null @@ -1,36 +0,0 @@ -Song Title Here - - -Chorus 1 -Lyrics -Lyrics -Lyrics -Lyrics - - -Verse 1 -Lyrics -Lyrics -Lyrics - - -Verse 2 -Lyrics -Lyrics -Lyrics - - -Misc 1 -(BRIDGE) -Lyrics -Lyrics -Lyrics -Lyrics - - - -CCLI Song No. 1234567 -© 1996 Publisher Info -Author/artist name -For use solely in accordance with the SongSelect Advanced Terms of Agreement. All rights Reserved. -CCLI License No. 1234567 \ No newline at end of file diff --git a/openlp/plugins/songs/test/data_text/PÃ¥EnFjern.txt b/openlp/plugins/songs/test/data_text/PÃ¥EnFjern.txt deleted file mode 100644 index 34a6da1ce..000000000 --- a/openlp/plugins/songs/test/data_text/PÃ¥EnFjern.txt +++ /dev/null @@ -1,61 +0,0 @@ -På en fjern ensom høj - -Verse 1 -På en fjern ensom høj, -Jesu kors dyrest stod, -symbolet på smerte og skam. -O, jeg elsker det kors, -hvor Guds søn gjorde bod, -da forbandelsen blev lagt på ham. - -Chorus 1 -Jeg vil elske det urgamle kors, -i det kraft er der sejer og sang. -Lad mig favne det hellige kors, -det med kronen ombyttes engang. - -Verse 2 -O, det urgamle kors, -med sin hvile og fred, -tilhyllet i verdens foragt. -Se, det hellige lam, -som på Golgatha stred, -og til jorden Guds nåde har bragt. - -Chorus 2 -Jeg vil elske det urgamle kors, -i det kraft er der sejer og sang. -Lad mig favne det hellige kors, -det med kronen ombyttes engang. - -Verse 3 -I det urgamle kors, -i hans blod farvet rødt, -en underfuld skønhed jeg ser. -Ja, det var på det kors, -at han selv blev forstødt, -nu skal aldrig for dommen jeg mer. - -Chorus 3 -Jeg vil elske det urgamle kors, -i det kraft er der sejer og sang. -Lad mig favne det hellige kors, -det med kronen ombyttes engang. - -Verse 4 -For det urgamle kors, -står mit hjerte i brand, -min plads jeg nu har ved dets fod. -Til han kalder en dag, -mig til himmelens land, -og til hvilen hos Faderen god. - -Chorus 4 -Jeg vil elske det urgamle kors, -i det kraft er der sejer og sang. -Lad mig favne det hellige kors, -det med kronen ombyttes engang. - -CCLI Song No. -© -Georg Bennard diff --git a/openlp/plugins/songs/test/data_xml/amazing1.xml b/openlp/plugins/songs/test/data_xml/amazing1.xml deleted file mode 100644 index 9cc7e1b97..000000000 --- a/openlp/plugins/songs/test/data_xml/amazing1.xml +++ /dev/null @@ -1,22 +0,0 @@ - - -Amazing Grace - - -Amazing grace how sweet the sound that saved a wretch like me; -I once was lost but now I'm found, was blind but now I see. - - -Twas grace that taught my heart to fear, and grace my fears relieved; -How precious did that grace appear the hour I first believed! - - -Through many dangers, toils, and snares I have already come; -'Tis grace that brought me safe thus far and grace will lead me home. - - -When we've been there ten thousand years bright shining as the sun; -We've no less days to sing God's praise than when we'd first begun! - - - \ No newline at end of file diff --git a/openlp/plugins/songs/test/data_xml/amazing2.xml b/openlp/plugins/songs/test/data_xml/amazing2.xml deleted file mode 100644 index 8ea0666ef..000000000 --- a/openlp/plugins/songs/test/data_xml/amazing2.xml +++ /dev/null @@ -1,22 +0,0 @@ - - -Amazing Grace - - -Amazing grace how sweet the sound that saved a wretch like me; -I once was lost but now I'm found, was blind but now I see. - - -Twas grace that taught my heart to fear, and grace my fears relieved; -How precious did that grace appear the hour I first believed! - - -Through many dangers, toils, and snares I have already come; -'Tis grace that brought me safe thus far and grace will lead me home. - - -When we've been there ten thousand years bright shining as the sun; -We've no less days to sing God's praise than when we'd first begun! - - - \ No newline at end of file diff --git a/openlp/plugins/songs/test/data_xml/danish1.xml b/openlp/plugins/songs/test/data_xml/danish1.xml deleted file mode 100644 index ec53ac150..000000000 --- a/openlp/plugins/songs/test/data_xml/danish1.xml +++ /dev/null @@ -1,62 +0,0 @@ - - -PÃ¥ en fjern ensom høj - - -PÃ¥ en fjern ensom høj, -Jesu kors dyrest stod, -symbolet pÃ¥ smerte og skam. -O, jeg elsker det kors, -hvor Guds søn gjorde bod, -da forbandelsen blev lagt pÃ¥ ham. - - -Jeg vil elske det urgamle kors, -i det kraft er der sejer og sang. -Lad mig favne det hellige kors, -det med kronen ombyttes engang. - - -O, det urgamle kors, -med sin hvile og fred, -tilhyllet i verdens foragt. -Se, det hellige lam, -som pÃ¥ Golgatha stred, -og til jorden Guds nÃ¥de har bragt. - - -Jeg vil elske det urgamle kors, -i det kraft er der sejer og sang. -Lad mig favne det hellige kors, -det med kronen ombyttes engang. - - -I det urgamle kors, -i hans blod farvet rødt, -en underfuld skønhed jeg ser. -Ja, det var pÃ¥ det kors, -at han selv blev forstødt, -nu skal aldrig for dommen jeg mer. - - -Jeg vil elske det urgamle kors, -i det kraft er der sejer og sang. -Lad mig favne det hellige kors, -det med kronen ombyttes engang. - - -For det urgamle kors, -stÃ¥r mit hjerte i brand, -min plads jeg nu har ved dets fod. -Til han kalder en dag, -mig til himmelens land, -og til hvilen hos Faderen god. - - -Jeg vil elske det urgamle kors, -i det kraft er der sejer og sang. -Lad mig favne det hellige kors, -det med kronen ombyttes engang. - - - diff --git a/openlp/plugins/songs/test/data_xml/danish2.xml b/openlp/plugins/songs/test/data_xml/danish2.xml deleted file mode 100644 index e7edb5bf5..000000000 --- a/openlp/plugins/songs/test/data_xml/danish2.xml +++ /dev/null @@ -1,62 +0,0 @@ - - -På en fjern ensom høj - - -På en fjern ensom høj, -Jesu kors dyrest stod, -symbolet på smerte og skam. -O, jeg elsker det kors, -hvor Guds søn gjorde bod, -da forbandelsen blev lagt på ham. - - -Jeg vil elske det urgamle kors, -i det kraft er der sejer og sang. -Lad mig favne det hellige kors, -det med kronen ombyttes engang. - - -O, det urgamle kors, -med sin hvile og fred, -tilhyllet i verdens foragt. -Se, det hellige lam, -som på Golgatha stred, -og til jorden Guds nåde har bragt. - - -Jeg vil elske det urgamle kors, -i det kraft er der sejer og sang. -Lad mig favne det hellige kors, -det med kronen ombyttes engang. - - -I det urgamle kors, -i hans blod farvet rødt, -en underfuld skønhed jeg ser. -Ja, det var på det kors, -at han selv blev forstødt, -nu skal aldrig for dommen jeg mer. - - -Jeg vil elske det urgamle kors, -i det kraft er der sejer og sang. -Lad mig favne det hellige kors, -det med kronen ombyttes engang. - - -For det urgamle kors, -står mit hjerte i brand, -min plads jeg nu har ved dets fod. -Til han kalder en dag, -mig til himmelens land, -og til hvilen hos Faderen god. - - -Jeg vil elske det urgamle kors, -i det kraft er der sejer og sang. -Lad mig favne det hellige kors, -det med kronen ombyttes engang. - - - diff --git a/openlp/plugins/songs/test/data_xml/format1.xml b/openlp/plugins/songs/test/data_xml/format1.xml deleted file mode 100644 index f80ea8704..000000000 --- a/openlp/plugins/songs/test/data_xml/format1.xml +++ /dev/null @@ -1,22 +0,0 @@ - - -Amazing Grace - - -Amazing grace how sweet the sound that saved a wretch like me; -I once was lost but now I'm found, was blind but now I see. - - -Twas grace that taught my heart to fear, and grace my fears relieved; -How precious did that grace appear the hour I first believed! - - -Through many dangers, toils, and snares I have already come; -'Tis grace that brought me safe thus far and grace will lead me home. - - -When we've been there ten thousand years bright shining as the sun; -We've no less days to sing God's praise than when we'd first begun! - - - \ No newline at end of file diff --git a/openlp/plugins/songs/test/data_xml/sample1.xml b/openlp/plugins/songs/test/data_xml/sample1.xml deleted file mode 100644 index 11a8576ad..000000000 --- a/openlp/plugins/songs/test/data_xml/sample1.xml +++ /dev/null @@ -1,32 +0,0 @@ - - - - Amazing Grace - - name of verse specific theme - any text - - Amazing grace, how ... - - - A b c - D e f - - ... - - - any text - ... - - - - Erstaunliche Anmut - - Erstaunliche Anmut, wie - ... - - - ... - - - diff --git a/openlp/plugins/songs/test/test_song_basic.py b/openlp/plugins/songs/test/test_song_basic.py deleted file mode 100644 index 2cbfdd8ff..000000000 --- a/openlp/plugins/songs/test/test_song_basic.py +++ /dev/null @@ -1,182 +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, Christian Richter, 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 py.test -import os -import sys - -__ThisDir__ = os.path.dirname(__file__) -if "" == __ThisDir__ : - __ThisDir__ = os.path.abspath(u'.') - -sys.path.append(os.path.abspath(u'%s/../../../..'%__ThisDir__)) - -from openlp.plugins.songs.lib.songxml import * - -class Test_Basic(object): - """Class for first initialization check - set-get functions - """ - - def test_Creation(self): - """Init: Create as empty""" - s = Song() - assert(True) - - def test_Title1(self): - """Set an empty title - raises an exception""" - s = Song() - py.test.raises(SongTitleError, s.set_title, '') - - def test_Title2(self): - """Set a normal title""" - s = Song() - t = "A normal title" - s.set_title(t) - assert(s.get_title() == t) - assert(s.get_search_title() == t) - - def test_Title3(self): - """Set a titel with punctuation 1""" - s = Song() - t1 = "Hey! Come on, ya programmers*" - t2 = "Hey Come on ya programmers" - s.set_title(t1) - assert(s.get_title() == t1) - assert(s.get_search_title() == t2) - - def test_Title4(self): - """Set a titel with punctuation 2""" - s = Song() - t1 = "??#Hey! Come on, ya programmers*" - t2 = "Hey Come on ya programmers" - s.set_title(t1) - assert(s.get_title() == t1) - assert(s.get_search_title() == t2) - - def test_Title5(self): - """ - Set a title - Where searchable title becomes empty raises an exception - """ - s = Song() - py.test.raises(SongTitleError, s.set_title, ',*') - - def test_Copyright(self): - """Set a copyright string""" - s = Song() - assert(s.get_copyright() == '') - s.set_copyright(u'A B Car') - assert(s.get_copyright() == 'A B Car') - - def test_SongCclino(self): - """Set a SongCcliNo""" - s = Song() - assert(s.get_song_cclino() == '') - s.set_song_cclino(12345) - assert(s.get_song_cclino() == '12345') - - def test_SongBook(self): - """Set a songbook value""" - s = Song() - assert(s.get_song_book() == '') - s.set_song_book(u'Hymns') - assert(s.get_song_book() == u'Hymns') - - def test_SongNumber(self): - """Set a song number""" - s = Song() - assert(s.get_song_number() == '') - s.set_song_number(278) - assert(s.get_song_number() == '278') - - def test_Theme(self): - """Set a theme name""" - s = Song() - assert(s.get_theme() == '') - s.set_theme(u'Red') - assert(s.get_theme() == 'Red') - - def test_VerseOrder(self): - """Set a verse order""" - s = Song() - assert(s.get_verse_order() == '') - s.set_verse_order(u'V1 C V2') - assert(s.get_verse_order() == 'V1 C V2') - - def test_Comments(self): - """Set a comment""" - s = Song() - assert(s.get_comments() == '') - s.set_comments(u'a comment') - assert(s.get_comments() == 'a comment') - - def test_AuthorList(self): - """Set author lists""" - s = Song() - assert(s.get_author_list(True) == '') - assert(s.get_author_list(False) == []) - t1 = "John Newton" - s.set_author_list(t1) - assert(s.get_author_list(True) == t1) - assert(s.get_author_list(False) == [t1]) - s.set_author_list(u' Peter Done , John Newton') - assert(s.get_author_list(True)== 'Peter Done, John Newton') - assert(s.get_author_list(False) == ["Peter Done", u'John Newton']) - s.set_author_list(None) - assert(s.get_author_list(True) == '') - assert(s.get_author_list(False) == []) - s.set_author_list(u'') - assert(s.get_author_list(True) == '') - assert(s.get_author_list(False) == [""]) - s.set_author_list([]) - assert(s.get_author_list(True) == '') - assert(s.get_author_list(False) == [""]) - - def test_CategoryArray(self): - """Set categories""" - s = Song() - assert(s.get_category_array(True) == '') - assert(s.get_category_array(False) == []) - t1 = "Gospel" - s.set_category_array(t1) - assert(s.get_category_array(True) == t1) - assert(s.get_category_array(False) == [t1]) - s.set_category_array(u' Gospel, Hymns ') - assert(s.get_category_array(True) == 'Gospel, Hymns') - assert(s.get_category_array(False) == ["Gospel", u'Hymns']) - s.set_category_array(None) - assert(s.get_category_array(True) == '') - assert(s.get_category_array(False) == []) - s.set_category_array(u'') - assert(s.get_category_array(True) == '') - assert(s.get_category_array(False) == [""]) - s.set_category_array([]) - assert(s.get_category_array(True) == '') - assert(s.get_category_array(False) == [""]) - -if '__main__' == __name__: - r = Test_Basic() - r.test_asString() diff --git a/openlp/plugins/songs/test/test_song_opensong.py b/openlp/plugins/songs/test/test_song_opensong.py deleted file mode 100644 index d0c716d7d..000000000 --- a/openlp/plugins/songs/test/test_song_opensong.py +++ /dev/null @@ -1,192 +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, Christian Richter, 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 sys - -__ThisDir__ = os.path.dirname(__file__) -if "" == __ThisDir__ : - __ThisDir__ = os.path.abspath(u'.') - -sys.path.append(os.path.abspath(u'%s/../../../..'%__ThisDir__)) - -from openlp.plugins.songs.lib.songxml import * - - -_sample1 = \ -''' - - - - - - - - [V1] -. chord line 1 - verse 1 line 1 -. chord line 2 - verse 1 line 2 - -[V2] - verse 2 line 1 - verse 2 line 2 - -[V3] - verse 3 line 1 - verse 3 line 2 - -[C] -. chorus chord line 1 - chorus line 1 -. chorus chord line 2 - chorus line 2 - -''' - -_sample2 = \ -''' - - - - - - - - [V] -1verse 1 line 1 -2verse 2 line 1 -3verse 3 line 1 -1verse 1 line 2 -2verse 2 line 2 -3verse 3 line 2 - -[C] - chorus line 1 - chorus line 2 - -''' - -_sample3 = \ -''' - - - - - - - - [V] -1verse 1 line 1 -2verse 2 line 1 -3verse 3 line 1 -1verse 1 line 2 -2verse 2 line 2 -3verse 3 line 2 - -[C] - chorus line 1 - chorus line 2 - -[P] - pre-chorus line 1 - pre-chorus line 2 - pre-chorus line 3 - -[B] - bridge line 1 - bridge line 2 - - -''' - -class Test_OpenSong(object): - """Test cases for converting from OpenSong xml format to Song""" - - def test_sample1(self): - """OpenSong: handwritten sample1""" - s = Song() - s.from_opensong_buffer(_sample1) - l = s.get_lyrics() - assert(len(l) == (4*3+3)) - assert(s.get_number_of_slides() == 4) - - def test_sample2(self): - """OpenSong: handwritten sample2 - with verses and chorus""" - s = Song() - s.from_opensong_buffer(_sample2) - l = s.get_lyrics() - assert(len(l) == (4*3+3)) - assert(s.get_number_of_slides() == 4) - - def test_sample3(self): - """OpenSong: handwritten sample3 - with verses, chorus, bridge and pre-chorus""" - s = Song() - s.from_opensong_buffer(_sample3) - l = s.get_lyrics() - assert(len(l) == (4*3+4+5+4)) - assert(s.get_number_of_slides() == 6) - - def test_file1(self): - """OpenSong: parse Amazing Grace""" - global __ThisDir__ - s = Song() - s.from_opensong_file(u'%s/data_opensong/Amazing Grace'%(__ThisDir__)) - assert(s.get_title() == 'Amazing Grace') - assert(s.get_copyright() == '1982 Jubilate Hymns Limited') - assert(s.get_song_cclino() == '1037882') - assert(s.get_category_array(True) == 'God: Attributes') - assert(s.get_author_list(True) == 'John Newton') - assert(s.get_verse_order() == '') - assert(s.get_number_of_slides() == 4) - - def test_file2(self): - """OpenSong: parse The Solid Rock""" - s = Song() - s.from_opensong_file(u'%s/data_opensong/The Solid Rock'%(__ThisDir__)) - assert(s.get_title() == 'The Solid Rock') - assert(s.get_copyright() == 'Public Domain') - assert(s.get_song_cclino() == '101740') - assert(s.get_category_array(True) == 'Christ: Victory, Fruit: Peace/Comfort') - assert(s.get_author_list(True) == 'Edward Mote, John B. Dykes') - assert(s.get_verse_order() == 'V1 C V2 C V3 C V4 C') - assert(s.get_number_of_slides() == 5) - - def test_file3(self): - """OpenSong: parse 'PÃ¥ en fjern ensom høj' (danish)""" - #FIXME: problem with XML convert and danish characters - s = Song() - s.from_opensong_file(u'%s/data_opensong/PÃ¥ en fjern ensom høj'%(__ThisDir__)) - assert(s.get_title() == u'PÃ¥ en fjern ensom høj') - assert(s.get_copyright() == '') - assert(s.get_song_cclino() == '') - assert(s.get_category_array(True) == '') - assert(s.get_author_list(True) == '') - assert(s.get_verse_order() == 'V1 C1 V2 C2 V3 C3 V4 C4') - assert(s.get_number_of_slides() == 8) - -if '__main__' == __name__: - r = Test_OpenSong() - r.test_file3() diff --git a/openlp/plugins/songs/test/test_song_text.py b/openlp/plugins/songs/test/test_song_text.py deleted file mode 100644 index 810428233..000000000 --- a/openlp/plugins/songs/test/test_song_text.py +++ /dev/null @@ -1,66 +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, Christian Richter, 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 sys - -__ThisDir__ = os.path.dirname(__file__) -if "" == __ThisDir__ : - __ThisDir__ = os.path.abspath(u'.') - -sys.path.append(os.path.abspath(u'%s/../../../..'%__ThisDir__)) - -from openlp.plugins.songs.lib.songxml import * - -class Test_Text(object): - """Test cases for converting from text format to Song""" - - def test_file1(self): - """OpenSong: parse CCLI example""" - global __ThisDir__ - s = Song() - s.from_ccli_text_file(u'%s/data_text/CCLI example.txt'%(__ThisDir__)) - assert(s.get_title() == 'Song Title Here') - assert(s.get_author_list(True) == 'Author, artist name') - assert(s.get_copyright() == '1996 Publisher Info') - assert(s.get_song_cclino() == '1234567') - assert(s.get_number_of_slides() == 4) - - def test_file2(self): - """OpenSong: parse PÃ¥EnFjern (danish)""" - global __ThisDir__ - s = Song() - s.from_ccli_text_file(u'%s/data_text/PÃ¥EnFjern.txt'%(__ThisDir__)) - assert(s.get_title() == 'PÃ¥ en fjern ensom høj') - assert(s.get_author_list(True) == 'Georg Bennard') - assert(s.get_copyright() == '') - assert(s.get_song_cclino() == '') - assert(s.get_number_of_slides() == 8) - -if '__main__' == __name__: - # for local debugging - r = Test_Text() - r.test_file1() - r.test_file2() diff --git a/openlp/plugins/songs/test/test_song_verse.py b/openlp/plugins/songs/test/test_song_verse.py deleted file mode 100644 index 7467bbb1b..000000000 --- a/openlp/plugins/songs/test/test_song_verse.py +++ /dev/null @@ -1,156 +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, Christian Richter, 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 sys - -__ThisDir__ = os.path.dirname(__file__) -if "" == __ThisDir__ : - __ThisDir__ = os.path.abspath(u'.') - -sys.path.append(os.path.abspath(u'%s/../../../..'%__ThisDir__)) - -from openlp.plugins.songs.lib.songxml import * - -class Test_Verse(object): - """Class for testing verses for preview and review""" - - def stdSong(self): - """Definition of a standard song""" - s = Song() - self.title = "A song" - self.author = "John Newton" - self.copyright = "Peter Hamil" - self.ccli = "123456" - s.set_lyrics(["# verse","a single line"]) - s.set_title(self.title) - s.set_copyright(self.copyright) - s.set_author_list(self.author) - s.set_song_cclino(self.ccli) - return s - - def check_allfields(self, r, isblank = 0): - #[theme, title, author, cpright, ccli, lyrics] - if isblank == 1 : - assert(r[1] == '') - else : - assert(r[1] == self.title) - if isblank == 2 : - assert(r[2] == '') - else : - assert(r[2] == self.author) - if isblank == 3 : - assert(r[3] == '') - else : - assert(r[3] == self.copyright) - if isblank == 4 : - assert(r[4] == '') - else : - assert(r[4] == self.ccli) - - - def test_title_show_noshow(self): - """Test the show title flag""" - s = self.stdSong() - r = s.get_render_slide(1) - self.check_allfields(r) - s.set_show_title(False) - r = s.get_render_slide(1) - self.check_allfields(r, 1) - s.set_show_title(True) - r = s.get_render_slide(1) - self.check_allfields(r) - - def test_author_show_noshow(self): - """Test the show author flag""" - s = self.stdSong() - r = s.get_render_slide(1) - self.check_allfields(r) - s.set_show_author_list(False) - r = s.get_render_slide(1) - self.check_allfields(r, 2) - s.set_show_author_list(True) - r = s.get_render_slide(1) - self.check_allfields(r) - - def test_copyright_show_noshow(self): - """Test the show copyright flag""" - s = self.stdSong() - r = s.get_render_slide(1) - self.check_allfields(r) - s.set_show_copyright(False) - r = s.get_render_slide(1) - self.check_allfields(r, 3) - s.set_show_copyright(True) - r = s.get_render_slide(1) - self.check_allfields(r) - - def test_ccli_show_noshow(self): - """Test the show copyright flag""" - s = self.stdSong() - r = s.get_render_slide(1) - self.check_allfields(r) - s.set_show_song_cclino(False) - r = s.get_render_slide(1) - self.check_allfields(r, 4) - s.set_show_song_cclino(True) - r = s.get_render_slide(1) - self.check_allfields(r) - - def test_verse1(self): - """Test an empty verse list""" - s = Song() - s.set_lyrics([]) - assert(s.get_number_of_slides() == 0) - - def test_verse2(self): - """Test a list with an empty string""" - s = Song() - s.set_lyrics([""]) - assert(s.get_number_of_slides() == 0) - - def test_verse3a(self): - """Test a one liner song""" - s = Song() - s.set_lyrics(["Single verse"]) - assert(s.get_number_of_slides() == 1) - - def test_verse3b(self): - """Test a one liner song""" - s = Song() - s.set_lyrics(["", u'Single verse']) - assert(s.get_number_of_slides() == 1) - - def test_verse3c(self): - """Test a one liner song""" - s = Song() - s.set_lyrics(["", u'Single verse', u'', u'']) - assert(s.get_number_of_slides() == 1) - - def test_verse3d(self): - """Test a one liner song""" - s = Song() - s.set_lyrics(["", u'# Verse', u'', u'']) - assert(s.get_number_of_slides() == 1) diff --git a/resources/i18n/openlp_en.ts b/resources/i18n/openlp_en.ts index 425c8cbb6..aeb147e66 100644 --- a/resources/i18n/openlp_en.ts +++ b/resources/i18n/openlp_en.ts @@ -11,8 +11,18 @@ AlertsTab - - Alerts + + pt + + + + + Location: + + + + + Font Color: @@ -26,23 +36,13 @@ - - Font Color: + + Preview - - Background Color: - - - - - Font Size: - - - - - pt + + Alerts @@ -51,13 +51,8 @@ - - s - - - - - Location: + + openlp.org @@ -66,13 +61,18 @@ - - Preview + + Background Color: - - openlp.org + + s + + + + + Bottom @@ -81,8 +81,8 @@ - - Bottom + + Font Size: @@ -124,8 +124,8 @@ AmendThemeForm - - Background Color: + + Slide Height is %s rows @@ -139,79 +139,44 @@ - - Slide Height is %s rows + + Background Color: AuthorsForm - - - Error - - You need to type in the first name of the author. - - - You need to type in the last name of the author. - - You haven't set a display name for the author, would you like me to combine the first and last names for you? + + + Error + + + + + You need to type in the last name of the author. + + BibleMediaItem - - - Bible - - Quick - - Advanced - - - - - Version: - - - - - Dual: - - - - - Search Type: - - - - - Find: - - - - - Search - - - - - Results: + + Bible @@ -219,49 +184,24 @@ Book: - - - Chapter: - - - - - Verse: - - - - - From: - - - - - To: - - - - - Verse Search - - Text Search - - Clear + + Find: - - Keep + + Search Type: - - No Book Found + + Bible not fully loaded @@ -270,8 +210,68 @@ - - Bible not fully loaded + + Dual: + + + + + Chapter: + + + + + Search + + + + + Keep + + + + + Results: + + + + + Verse Search + + + + + Version: + + + + + From: + + + + + No Book Found + + + + + Advanced + + + + + To: + + + + + Clear + + + + + Verse: @@ -286,8 +286,28 @@ BiblesTab - - Bibles + + ( and ) + + + + + verse per line + + + + + Display Style: + + + + + continuous + + + + + [ and ] @@ -295,6 +315,11 @@ Verse Display + + + Display Dual Bible Verses + + Only show new chapter numbers @@ -305,39 +330,14 @@ Layout Style: - - - Display Style: - - - - - Bible Theme: - - - - - verse per slide - - - - - verse per line - - - - - continuous - - No brackets - - ( and ) + + Bibles @@ -345,11 +345,6 @@ { and } - - - [ and ] - - Note: @@ -357,8 +352,13 @@ Changes don't affect verses already in the service - - Display Dual Bible Verses + + verse per slide + + + + + Bible Theme: @@ -386,26 +386,21 @@ Changes don't affect verses already in the service - - Custom Display + + Display Footer: - - Display Footer: + + Custom Display EditCustomForm - - Save && Preview - - - - - Error + + You have unsaved data @@ -413,24 +408,24 @@ Changes don't affect verses already in the service You need to enter a title + + + Error + + You need to enter a slide - - You have unsaved data + + Save && Preview EditSongForm - - - Save && Preview - - You need to enter a song title. @@ -441,9 +436,19 @@ Changes don't affect verses already in the service You need to enter some verses. + + + Save && Preview + + + + + Error + + - bcitped + bitped @@ -452,152 +457,137 @@ Changes don't affect verses already in the service - - Invalid verse entry - vX + + c - - Invalid verse entry - values must be Numeric, I,B,C,T,P,E,O + + Invalid verse entry - Vx or Cx - - Error + + Invalid verse entry, values must be I,B,T,P,E,O,Vx,Cx EditVerseForm - - Intro - - - - - Ending - - - - - Other - - - - - Pre-Chorus - - - - - Bridge - - - - - Chorus - - - - + Verse + + + Chrous + + GeneralTab - - General - - - - - Monitors - - - - - Select monitor for output display: - - - - - Application Startup - - - - - Show blank screen warning - - - - - Automatically open the last service - - - - - Show the splash screen - - - - - Application Settings - - - - - Prompt to save Service before starting New - - - - - Preview Next Song from Service Manager - - - - + CCLI Details - - CCLI Number: + + primary - + + Application Startup + + + + + Select monitor for output display: + + + + + Application Settings + + + + SongSelect Username: - - SongSelect Password: + + CCLI Number: - + + Automatically open the last service + + + + + Preview Next Song from Service Manager + + + + + Show blank screen warning + + + + + Prompt to save Service before starting New + + + + + General + + + + + Show the splash screen + + + + Screen - - primary + + Monitors + + + + + SongSelect Password: + + + + + Display if in single screen ImageMediaItem - - Image + + Select Image(s) - - Select Image(s) + + Image(s) + + + + + Image @@ -610,11 +600,6 @@ Changes don't affect verses already in the service Replace Live Background - - - Image(s) - - No item selected @@ -637,8 +622,8 @@ Changes don't affect verses already in the service ImageTab - - Images + + sec @@ -652,66 +637,21 @@ Changes don't affect verses already in the service - - sec + + Images ImportWizardForm - - - Invalid Bible Location - - - - - You need to specify a file to import your Bible from. - - - - - Invalid Books File - - You need to specify a file with books of the Bible to use in the import. - - Invalid Verse File - - - - - You need to specify a file of Bible verses to import. - - - - - Invalid OpenSong Bible - - - - - You need to specify an OpenSong Bible file to import. - - - - - Empty Version Name - - - - - You need to specify a version name for your Bible. - - - - - Empty Copyright + + Invalid Bible Location @@ -724,11 +664,76 @@ Changes don't affect verses already in the service Bible Exists + + + Empty Copyright + + + + + Empty Version Name + + + + + Invalid OpenSong Bible + + + + + Your Bible import failed. + + + + + Finished import. + + + + + You need to specify a file of Bible verses to import. + + + + + You need to specify a version name for your Bible. + + This Bible already exists! Please import a different Bible or first delete the existing one. + + + Starting import... + + + + + Invalid Books File + + + + + You need to specify a file to import your Bible from. + + + + + You need to specify an OpenSong Bible file to import. + + + + + Invalid Verse File + + + + + Open OpenSong Bible + + Open OSIS File @@ -744,67 +749,52 @@ Changes don't affect verses already in the service Open Verses CSV File - - - Open OpenSong Bible - - - - - Starting import... - - - - - Finished import. - - - - - Your Bible import failed. - - MainWindow - - Version %s of OpenLP is now available for download (you are currently running version %s). - -You can download the latest version from http://openlp.org - - - - - OpenLP Version Updated - - - - - OpenLP Main Display Blanked - - - - + The Main Display has been blanked out - + + OpenLP Version Updated + + + + Save Changes to Service? - + Your service has changed, do you want to save those changes? + + + OpenLP Main Display Blanked + + + + + Version %s of OpenLP is now available for download (you are currently running version %s). + +You can download the latest version from http://openlp.org + + MediaManagerItem - - Import a + + &Preview + + + + + You must select one or more items @@ -812,24 +802,19 @@ You can download the latest version from http://openlp.org Load a new - - - Add a new - - - - - Edit the selected - - Delete the selected item - - Preview the selected item + + &Edit + + + + + &Add to Service @@ -843,18 +828,13 @@ You can download the latest version from http://openlp.org - - &Edit + + Edit the selected - - &Delete - - - - - &Preview + + Add a new @@ -863,8 +843,18 @@ You can download the latest version from http://openlp.org - - &Add to Service + + Preview the selected item + + + + + Import a + + + + + &Delete @@ -887,11 +877,6 @@ You can download the latest version from http://openlp.org No items selected - - - You must select one or more items - - No Service Item Selected @@ -911,17 +896,17 @@ You can download the latest version from http://openlp.org MediaMediaItem - + Media - + Select Media - + Videos (%s);;Audio (%s);;All files (*) @@ -950,8 +935,8 @@ You can download the latest version from http://openlp.org - - Select Presentation(s) + + Present using: @@ -960,13 +945,13 @@ You can download the latest version from http://openlp.org - - Presentations (%s) + + A presentation with that filename already exists. - - Present using: + + Select Presentation(s) @@ -975,8 +960,8 @@ You can download the latest version from http://openlp.org - - A presentation with that filename already exists. + + Presentations (%s) @@ -990,11 +975,6 @@ You can download the latest version from http://openlp.org PresentationTab - - - Presentations - - Available Controllers @@ -1005,6 +985,11 @@ You can download the latest version from http://openlp.org available + + + Presentations + + RemoteTab @@ -1030,13 +1015,8 @@ You can download the latest version from http://openlp.org ServiceManager - - New Service - - - - - Create a new service + + Save Changes to Service? @@ -1045,13 +1025,13 @@ You can download the latest version from http://openlp.org - - Load an existing service + + Move to top - - Save Service + + Create a new service @@ -1064,19 +1044,49 @@ You can download the latest version from http://openlp.org Theme: + + + Delete From Service + + + + + Save Service + + + + + &Live Verse + + Move to &top - - Move to top + + New Service - - Move &up + + &Notes + + + + + Move to end + + + + + Your service is unsaved, do you want to save those changes before creating a new one ? + + + + + &Delete From Service @@ -1084,49 +1094,19 @@ You can download the latest version from http://openlp.org Move up order - - - Move &down - - Move down order - - Move to &bottom + + Move &down - - Move to end - - - - - &Delete From Service - - - - - Delete From Service - - - - - &Edit Item - - - - - &Maintain Item - - - - - &Notes + + Load an existing service @@ -1135,113 +1115,123 @@ You can download the latest version from http://openlp.org - - &Live Verse + + Move &up - - Save Changes to Service? + + &Edit Item - - Your service is unsaved, do you want to save those changes before creating a new one ? + + Move to &bottom + + + + + &Maintain Item SlideController - - Live - - - - - Preview - - - - - Move to first - - - - + Move to previous - - Move to next - - - - - Move to last - - - - - Blank Screen - - - - - Theme Screen - - - - - Hide Screen - - - - - Move to live - - - - - Edit and re-preview Song - - - - - Start continuous loop - - - - - Stop continuous loop - - - - - s - - - - - Delay between slides in seconds - - - - - Start playing media - - - - + Go to Verse - + + Start continuous loop + + + + + Live + + + + + Start playing media + + + + + Move to live + + + + + Preview + + + + + Move to last + + + + + Edit and re-preview Song + + + + + Delay between slides in seconds + + + + + Move to next + + + + + Move to first + + + + + Blank Screen + + + + Verse + + + Stop continuous loop + + + + + s + + + + + Theme Screen + + + + + Hide Screen + + + + + Chorus + + SongBookForm @@ -1259,18 +1249,18 @@ You can download the latest version from http://openlp.org SongMaintenanceForm - - Error + + Are you sure you want to delete the selected book? - - Couldn't add your author. + + Couldn't save your author. - - Couldn't add your topic. + + This author can't be deleted, they are currently assigned to at least one song. @@ -1279,8 +1269,43 @@ You can download the latest version from http://openlp.org - - Couldn't save your author. + + Error + + + + + No author selected! + + + + + Couldn't add your topic. + + + + + This book can't be deleted, it is currently assigned to at least one song. + + + + + Delete Book + + + + + No book selected! + + + + + Are you sure you want to delete the selected author? + + + + + Couldn't add your author. @@ -1293,34 +1318,19 @@ You can download the latest version from http://openlp.org Couldn't save your book. - - - Delete Author - - - - - Are you sure you want to delete the selected author? - - - - - This author can't be deleted, they are currently assigned to at least one song. - - - - - No author selected! - - Delete Topic + + + Delete Author + + - Are you sure you want to delete the selected topic? + No topic selected! @@ -1330,40 +1340,20 @@ You can download the latest version from http://openlp.org - No topic selected! - - - - - Delete Book - - - - - Are you sure you want to delete the selected book? - - - - - This book can't be deleted, it is currently assigned to at least one song. - - - - - No book selected! + Are you sure you want to delete the selected topic? SongMediaItem - - Song + + CCLI Licence: - - Song Maintenance + + Song @@ -1372,8 +1362,8 @@ You can download the latest version from http://openlp.org - - Search: + + Lyrics @@ -1381,6 +1371,11 @@ You can download the latest version from http://openlp.org Type: + + + Titles + + Clear @@ -1391,29 +1386,39 @@ You can download the latest version from http://openlp.org Search - - - Titles - - - - - Lyrics - - Authors + + + Search: + + + + + Song Maintenance + + %s (%s) - - CCLI Licence: + + Delete song? + + + + + Delete %d song? + + + + + Delete Confirmation @@ -1449,21 +1454,21 @@ You can download the latest version from http://openlp.org SongsPlugin - + <b>Song Plugin</b> <br>This plugin allows Songs to be managed and displayed.<br> + + + Open Songs of Fellowship file + + SongsTab - - Songs - - - - - Songs Mode + + Display Verses on Live Tool bar: @@ -1472,16 +1477,21 @@ You can download the latest version from http://openlp.org - - Display Verses on Live Tool bar: + + Songs Mode + + + + + Songs ThemeManager - - New Theme + + Import Theme @@ -1489,76 +1499,106 @@ You can download the latest version from http://openlp.org Create a new theme - - - Edit Theme - - - - - Edit a theme - - Delete Theme - - - Delete a theme - - - - - Import Theme - - - - - Import a theme - - - - - Export Theme - - - - - Export a theme - - - - - Delete theme - - - - - Make Global - - - - - Export theme - - - - - default - - Error + + + Make Global + + + + + Delete a theme + + + + + File is not a valid theme. + + + + + Edit a theme + + + + + Edit Theme + + + + + Export Theme + + You are unable to delete the default theme. + + + Theme Exists + + + + + Delete theme + + + + + Save Theme - (%s) + + + + + default + + + + + Select Theme Import File + + + + + New Theme + + + + + Import a theme + + + + + Export theme + + + + + You have not selected a theme. + + + + + A theme with this name already exists, would you like to overwrite it? + + + + + Export a theme + + Theme %s is use in %s plugin @@ -1569,42 +1609,12 @@ You can download the latest version from http://openlp.org Theme %s is use by Service Manager - - - You have not selected a theme. - - - - - Save Theme - (%s) - - - - - Select Theme Import File - - - - - File is not a valid theme. - - - - - Theme Exists - - - - - A theme with this name already exists, would you like to overwrite it? - - ThemesTab - - Themes + + Theme level @@ -1613,13 +1623,8 @@ You can download the latest version from http://openlp.org - - Theme level - - - - - Song level + + Use the global theme, overriding any themes associated with either the service or the songs. @@ -1632,19 +1637,24 @@ You can download the latest version from http://openlp.org Service level - - - Use the theme from the service, overriding any of the individual songs' themes. If the service doesn't have a theme, then use the global theme. - - Global level - - Use the global theme, overriding any themes associated with either the service or the songs. + + Song level + + + + + Use the theme from the service, overriding any of the individual songs' themes. If the service doesn't have a theme, then use the global theme. + + + + + Themes @@ -1652,22 +1662,47 @@ You can download the latest version from http://openlp.org TopicsForm - Error + You need to type in a topic name! - You need to type in a topic name! + Error Ui_AboutDialog + + + Close + + + + + License + + + + + Credits + + About OpenLP + + + About + + + + + Contribute + + OpenLP <version><revision> - Open Source Lyrics Projection @@ -1679,11 +1714,6 @@ Find out more about OpenLP: http://openlp.org/ OpenLP is written and maintained by volunteers. If you would like to see more free Christian software being written, please consider contributing by using the button below. - - - About - - Project Lead @@ -1717,34 +1747,19 @@ Packagers - - - Credits - - Copyright - - - License - - - - - Contribute - - - - - Close - - Ui_AlertDialog + + + Display + + Alert Message @@ -1755,11 +1770,6 @@ Packagers Alert Text: - - - Display - - Cancel @@ -1769,43 +1779,18 @@ Packagers Ui_AmendThemeDialog - - Theme Maintenance + + Shadow Size: - - Theme Name: + + Slide Transition - - Background: - - - - - Opaque - - - - - Transparent - - - - - Background Type: - - - - - Solid Color - - - - - Gradient + + Bottom @@ -1814,43 +1799,13 @@ Packagers - - <Color1> + + Height: - - <Color2> - - - - - Image: - - - - - Gradient : - - - - - Horizontal - - - - - Vertical - - - - - Circular - - - - - Background + + Outline @@ -1859,28 +1814,68 @@ Packagers - - Font: + + Solid Color - - Font Color: + + Font Main - - Size: + + Use Default Location: - - pt + + Other Options - - Wrap Indentation + + Shadow + + + + + Italics + + + + + Background: + + + + + X Position: + + + + + Center + + + + + <Color2> + + + + + Opaque + + + + + Outline Color: + + + + + Alignment @@ -1893,99 +1888,54 @@ Packagers Bold - - - Italics - - - - - Bold/Italics - - - - - Font Weight: - - - - - Display Location - - - - - Use Default Location: - - - - - X Position: - - - - - Y Position: - - - - - Width: - - - - - Height: - - - - - px - - - - - Font Main - - Footer Font + + + Theme Maintenance + + + + + <Color1> + + Font Footer - - Outline + + Font Weight: - - Outline Size: + + Transparent - - Outline Color: + + Background - - Show Outline: + + Vertical - - Shadow + + Width: - - Shadow Size: + + Middle @@ -1993,36 +1943,6 @@ Packagers Shadow Color: - - - Show Shadow: - - - - - Alignment - - - - - Horizontal Align: - - - - - Left - - - - - Right - - - - - Center - - Vertical Align: @@ -2034,18 +1954,83 @@ Packagers - - Middle + + Right - - Bottom + + Font Color: - - Slide Transition + + Horizontal + + + + + Circular + + + + + pt + + + + + px + + + + + Display Location + + + + + Y Position: + + + + + Show Shadow: + + + + + Font: + + + + + Preview + + + + + Outline Size: + + + + + Wrap Indentation + + + + + Left + + + + + Theme Name: + + + + + Image: @@ -2054,26 +2039,46 @@ Packagers - - Other Options + + Size: - - Preview + + Gradient : + + + + + Bold/Italics + + + + + Horizontal Align: + + + + + Background Type: + + + + + Show Outline: + + + + + Gradient Ui_AuthorsDialog - - Author Maintenance - - - - - Display name: + + Last name: @@ -2082,8 +2087,13 @@ Packagers - - Last name: + + Author Maintenance + + + + + Display name: @@ -2095,33 +2105,13 @@ Packagers - - Welcome to the Bible Import Wizard + + Bible: - - This wizard will help you to import Bibles from a variety of formats. Click the next button below to start the process by selecting a format to import from. - - - - - Select Import Source - - - - - Select the import format, and where to import from. - - - - - Format: - - - - - OSIS + + Crosswalk @@ -2134,89 +2124,14 @@ Packagers OpenSong - - - Web Download - - File Location: - - Books Location: - - - - - Verse Location: - - - - - Bible Filename: - - - - - Location: - - - - - Crosswalk - - - - - BibleGateway - - - - - Bible: - - - - - Download Options - - - - - Server: - - - - - Username: - - - - - Password: - - - - - Proxy Server (Optional) - - - - - License Details - - - - - Set up the Bible's license details. - - - - - Version Name: + + This wizard will help you to import Bibles from a variety of formats. Click the next button below to start the process by selecting a format to import from. @@ -2224,37 +2139,127 @@ Packagers Copyright: + + + Verse Location: + + + + + Server: + + Permission: + + + Select Import Source + + + + + Set up the Bible's license details. + + + + + BibleGateway + + + + + Username: + + + + + Download Options + + + + + Location: + + + + + Bible Filename: + + + + + Format: + + Importing + + + License Details + + + + + OSIS + + + + + Web Download + + Please wait while your Bible is imported. + + + Select the import format, and where to import from. + + + + + Proxy Server (Optional) + + + + + Welcome to the Bible Import Wizard + + + + + Password: + + + + + Version Name: + + Ready. + + + Books Location: + + Ui_EditSongDialog - - Song Editor - - - - - Title: + + &Remove @@ -2263,68 +2268,8 @@ Packagers - - Lyrics: - - - - - Verse Order: - - - - - Add - - - - - Edit - - - - - Edit All - - - - - Delete - - - - - Title && Lyrics - - - - - Authors - - - - - &Add to Song - - - - - &Remove - - - - - &Manage Authors, Topics, Books - - - - - Topic - - - - - A&dd to Song + + Add a Theme @@ -2333,13 +2278,13 @@ Packagers - - Song Book + + Verse Order: - - Authors, Topics && Book + + Title && Lyrics @@ -2348,8 +2293,8 @@ Packagers - - Add a Theme + + Authors, Topics && Book @@ -2357,85 +2302,145 @@ Packagers Copyright Information + + + Topic + + + + + Lyrics: + + + + + Edit + + + + + Authors + + + + + Song Editor + + + + + Delete + + + + + &Add to Song + + CCLI Number: + + + Add + + + + + Theme, Copyright Info && Comments + + + + + Song Book + + + + + Edit All + + + + + A&dd to Song + + + + + Title: + + Comments - - Theme, Copyright Info && Comments + + &Manage Authors, Topics, Books Ui_EditVerseDialog - - - Edit Verse - - - - - Verse Type - - - - - Intro - - Verse - - - Pre-Chorus - - - - - Chorus - - - - - Bridge - - Ending + + + Number + + Other - - Number + + Bridge + + + + + Pre-Chorus + + + + + Edit Verse + + + + + Intro + + + + + Chorus + + + + + Verse Type Ui_MainWindow - - OpenLP 2.0 - - - - - Default Theme: + + Open an existing service @@ -2444,78 +2449,13 @@ Packagers - - &Import + + List the Plugins - - &Export - - - - - &Options - - - - - &View - - - - - M&ode - - - - - &Tools - - - - - &Help - - - - - Media Manager - - - - - Service Manager - - - - - Theme Manager - - - - - &New - - - - - New Service - - - - - Create a new Service - - - - - Ctrl+N - - - - - &Open + + &Service Manager @@ -2524,58 +2464,33 @@ Packagers - - Open an existing service + + Media Manager - - Ctrl+O + + Alt+F4 - - &Save + + Toggle the visibility of the Preview Panel - - Save Service + + &User Guide - - Save the current service to disk + + Set the interface language to English - - Ctrl+S - - - - - Save &As... - - - - - Save Service As - - - - - Save the current service under a new name - - - - - F12 - - - - - E&xit + + &Import @@ -2584,8 +2499,143 @@ Packagers - - Alt+F4 + + &Preview Panel + + + + + &New + + + + + Default Theme: + + + + + Toggle Preview Panel + + + + + &Settings + + + + + &Live + + + + + English + + + + + F9 + + + + + F8 + + + + + Save the current service to disk + + + + + Add &Tool... + + + + + &View + + + + + &Export + + + + + &Open + + + + + Toggle Theme Manager + + + + + &Options + + + + + Ctrl+S + + + + + Ctrl+O + + + + + Ctrl+N + + + + + E&xit + + + + + &Help + + + + + Toggle Service Manager + + + + + Ctrl+F1 + + + + + Save the current service under a new name + + + + + &Web Site + + + + + M&ode + + + + + Translate the interface to your language + + + + + Service Manager @@ -2599,93 +2649,8 @@ Packagers - - Look && &Feel - - - - - &Settings - - - - - &Media Manager - - - - - Toggle Media Manager - - - - - Toggle the visibility of the Media Manager - - - - - F8 - - - - - &Theme Manager - - - - - Toggle Theme Manager - - - - - Toggle the visibility of the Theme Manager - - - - - F10 - - - - - &Service Manager - - - - - Toggle Service Manager - - - - - Toggle the visibility of the Service Manager - - - - - F9 - - - - - &Preview Panel - - - - - Toggle Preview Panel - - - - - Toggle the visibility of the Preview Panel - - - - - F11 + + &About @@ -2694,33 +2659,13 @@ Packagers - - List the Plugins + + &Translate - - Alt+F7 - - - - - &User Guide - - - - - &About - - - - - More information about OpenLP - - - - - Ctrl+F1 + + New Service @@ -2729,33 +2674,38 @@ Packagers - - &Web Site + + Save Service - - &Translate + + Save &As... - - Translate the interface to your language + + Toggle the visibility of the Media Manager - - English + + F11 - - Set the interface language to English + + F10 - - Add &Tool... + + F12 + + + + + Alt+F7 @@ -2763,77 +2713,97 @@ Packagers Add an application to the list of tools + + + Theme Manager + + + + + Toggle the visibility of the Theme Manager + + &Preview Pane - - &Live + + Save Service As + + + + + Toggle the visibility of the Service Manager + + + + + More information about OpenLP + + + + + &Media Manager + + + + + &Tools + + + + + Toggle Media Manager + + + + + Create a new Service + + + + + &Theme Manager + + + + + &Save + + + + + OpenLP 2.0 + + + + + Look && &Feel Ui_OpenLPExportDialog - - - openlp.org Song Exporter - - - - - Select openlp.org export filename: - - - - - Full Song List - - Song Title - - - Author - - - - - Select All - - - - - Lyrics - - Title - - Song Export List + + Select openlp.org export filename: - - Remove Selected - - - - - Progress: - - - - - Ready to export + + Close @@ -2842,76 +2812,81 @@ Packagers - - Close + + Lyrics + + + + + Full Song List + + + + + Progress: + + + + + Remove Selected + + + + + Author + + + + + openlp.org Song Exporter + + + + + Song Export List + + + + + Ready to export + + + + + Select All Ui_OpenLPImportDialog - - - openlp.org Song Importer - - - - - Select openlp.org songfile to import: - - - - - Import File Song List - - - - - Song Title - - Author - - - Select All - - - - - Lyrics - - - - - Title - - - - - Song Import List - - - - - Remove Selected - - - - - Progress: - - Ready to import - - Import + + Progress: + + + + + openlp.org Song Importer + + + + + Song Import List + + + + + Import File Song List @@ -2919,37 +2894,47 @@ Packagers Close - - - Ui_OpenSongExportDialog - - OpenSong Song Exporter + + Select openlp.org songfile to import: - - Select OpenSong song folder: + + Lyrics - - Full Song List + + Import - + Song Title - - Author + + Select All - - Select All + + Title + + + + + Remove Selected + + + + + Ui_OpenSongExportDialog + + + Close @@ -2958,8 +2943,13 @@ Packagers - - Title + + Song Title + + + + + Select All @@ -2967,6 +2957,21 @@ Packagers Song Export List + + + Author + + + + + Title + + + + + OpenSong Song Exporter + + Remove Selected @@ -2977,6 +2982,11 @@ Packagers Progress: + + + Select OpenSong song folder: + + Ready to export @@ -2988,33 +2998,18 @@ Packagers - - Close + + Full Song List Ui_OpenSongImportDialog - - - OpenSong Song Importer - - OpenSong Folder: - - - Progress: - - - - - Ready to import - - Import @@ -3025,17 +3020,37 @@ Packagers Close + + + Progress: + + + + + OpenSong Song Importer + + + + + Ready to import + + Ui_PluginViewDialog - - Plugin List + + Plugin Details - - Plugin Details + + Active + + + + + Status: @@ -3053,21 +3068,16 @@ Packagers About: - - - Status: - - - - - Active - - Inactive + + + Plugin List + + Ui_ServiceItemEditDialog @@ -3111,13 +3121,13 @@ Packagers Ui_SongBookDialog - - Edit Book + + Name: - - Name: + + Edit Book @@ -3129,13 +3139,8 @@ Packagers Ui_SongMaintenanceDialog - - Song Maintenance - - - - - Authors + + Edit @@ -3143,19 +3148,14 @@ Packagers Topics - - - Books/Hymnals - - Add - - Edit + + Authors @@ -3163,6 +3163,16 @@ Packagers Delete + + + Song Maintenance + + + + + Books/Hymnals + + Ui_SongUsageDeleteDialog @@ -3174,6 +3184,11 @@ Packagers Ui_SongUsageDetailDialog + + + Report Location + + Song Usage Extraction @@ -3189,60 +3204,25 @@ Packagers to - - - Report Location - - Ui_TopicsDialog - - Topic Maintenance + + Topic name: - - Topic name: + + Topic Maintenance Ui_customEditDialog - - Move slide Up 1 - - - - - Move slide down 1 - - - - - Edit Custom Slides - - - - - Title: - - - - - Add New - - - - - Add new slide at bottom - - - - - Edit + + Delete selected slide @@ -3255,6 +3235,46 @@ Packagers Edit All + + + Add new slide at bottom + + + + + Clear + + + + + Delete + + + + + Theme: + + + + + Move slide Up 1 + + + + + Title: + + + + + Credits: + + + + + Edit Custom Slides + + Edit all slides @@ -3271,28 +3291,8 @@ Packagers - - Delete - - - - - Delete selected slide - - - - - Clear - - - - - Clear edit area - - - - - Theme: + + Move slide down 1 @@ -3301,18 +3301,23 @@ Packagers - - Credits: + + Edit + + + + + Add New + + + + + Clear edit area alertsPlugin - - - &Alert - - Show an alert message @@ -3323,6 +3328,11 @@ Packagers <b>Alerts Plugin</b><br>This plugin controls the displaying of alerts on the presentations screen + + + &Alert + + export_menu @@ -3332,22 +3342,22 @@ Packagers - + &Song - + OpenSong - + openlp.org 1.0 - + OpenLP 2.0 @@ -3360,33 +3370,57 @@ Packagers - + &Song - + OpenSong - + openlp.org 1.0 - - Export songs in openlp.org 1.0 format + + Import songs in openlp.org 1.0 format - + OpenLP 2.0 - - Export songs in OpenLP 2.0 format + + Import songs in OpenLP 2.0 format + + + + + Songs of Fellowship + + + + + Import songs from the VOLS1_2.RTF, sof3words.rtf and sof4words.rtf supplied with the music books + + + + + self.ImportSongMenu + + + Import Error + + + + + Error importing Songs of Fellowship file. +OpenOffice.org must be installed and you must be using an unedited copy of the RTF included with the Songs of Fellowship Music Editions diff --git a/resources/images/general_add.png b/resources/images/general_add.png new file mode 100644 index 000000000..7bb9b1be8 Binary files /dev/null and b/resources/images/general_add.png differ diff --git a/resources/images/general_delete.png b/resources/images/general_delete.png new file mode 100644 index 000000000..ef8e685e2 Binary files /dev/null and b/resources/images/general_delete.png differ diff --git a/resources/images/general_edit.png b/resources/images/general_edit.png new file mode 100644 index 000000000..84e345d22 Binary files /dev/null and b/resources/images/general_edit.png differ diff --git a/resources/images/general_export.png b/resources/images/general_export.png new file mode 100644 index 000000000..d26519b7f Binary files /dev/null and b/resources/images/general_export.png differ diff --git a/resources/images/general_import.png b/resources/images/general_import.png new file mode 100644 index 000000000..0ee789269 Binary files /dev/null and b/resources/images/general_import.png differ diff --git a/resources/images/general_live.png b/resources/images/general_live.png new file mode 100644 index 000000000..cb2be2258 Binary files /dev/null and b/resources/images/general_live.png differ diff --git a/resources/images/general_new.png b/resources/images/general_new.png new file mode 100644 index 000000000..8431237bd Binary files /dev/null and b/resources/images/general_new.png differ diff --git a/resources/images/general_open.png b/resources/images/general_open.png new file mode 100644 index 000000000..eb211e233 Binary files /dev/null and b/resources/images/general_open.png differ diff --git a/resources/images/general_preview.png b/resources/images/general_preview.png new file mode 100644 index 000000000..d196792bb Binary files /dev/null and b/resources/images/general_preview.png differ diff --git a/resources/images/general_save.png b/resources/images/general_save.png new file mode 100644 index 000000000..8072aea32 Binary files /dev/null and b/resources/images/general_save.png differ