diff --git a/openlp.pyw b/openlp.pyw
index 962109592..64ffb3321 100755
--- a/openlp.pyw
+++ b/openlp.pyw
@@ -25,254 +25,15 @@
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
-import os
-import sys
-import logging
+
# Import uuid now, to avoid the rare bug described in the support system:
# http://support.openlp.org/issues/102
# If https://bugs.gentoo.org/show_bug.cgi?id=317557 is fixed, the import can be
# removed.
import uuid
-from optparse import OptionParser
-from traceback import format_exception
-from PyQt4 import QtCore, QtGui
+from openlp.core import main
-from openlp.core.lib import Receiver, check_directory_exists
-from openlp.core.lib.ui import UiStrings
-from openlp.core.resources import qInitResources
-from openlp.core.ui.mainwindow import MainWindow
-from openlp.core.ui.firsttimelanguageform import FirstTimeLanguageForm
-from openlp.core.ui.firsttimeform import FirstTimeForm
-from openlp.core.ui.exceptionform import ExceptionForm
-from openlp.core.ui import SplashScreen, ScreenList
-from openlp.core.utils import AppLocation, LanguageManager, VersionThread, \
- get_application_version, DelayStartThread
-
-log = logging.getLogger()
-
-application_stylesheet = u"""
-QMainWindow::separator
-{
- border: none;
-}
-
-QDockWidget::title
-{
- border: 1px solid palette(dark);
- padding-left: 5px;
- padding-top: 2px;
- margin: 1px 0;
-}
-
-QToolBar
-{
- border: none;
- margin: 0;
- padding: 0;
-}
-"""
-
-class OpenLP(QtGui.QApplication):
- """
- The core application class. This class inherits from Qt's QApplication
- class in order to provide the core of the application.
- """
-
- args = []
-
- def exec_(self):
- """
- Override exec method to allow the shared memory to be released on exit
- """
- QtGui.QApplication.exec_()
- self.sharedMemory.detach()
-
- def run(self, args):
- """
- Run the OpenLP application.
- """
- # On Windows, the args passed into the constructor are
- # ignored. Not very handy, so set the ones we want to use.
- self.args.extend(args)
- # provide a listener for widgets to reqest a screen update.
- QtCore.QObject.connect(Receiver.get_receiver(),
- QtCore.SIGNAL(u'openlp_process_events'), self.processEvents)
- QtCore.QObject.connect(Receiver.get_receiver(),
- QtCore.SIGNAL(u'cursor_busy'), self.setBusyCursor)
- QtCore.QObject.connect(Receiver.get_receiver(),
- QtCore.SIGNAL(u'cursor_normal'), self.setNormalCursor)
- # Decide how many screens we have and their size
- screens = ScreenList(self.desktop())
- # First time checks in settings
- has_run_wizard = QtCore.QSettings().value(
- u'general/has run wizard', QtCore.QVariant(False)).toBool()
- if not has_run_wizard:
- if FirstTimeForm(screens).exec_() == QtGui.QDialog.Accepted:
- QtCore.QSettings().setValue(u'general/has run wizard',
- QtCore.QVariant(True))
- if os.name == u'nt':
- self.setStyleSheet(application_stylesheet)
- show_splash = QtCore.QSettings().value(
- u'general/show splash', QtCore.QVariant(True)).toBool()
- if show_splash:
- self.splash = SplashScreen()
- self.splash.show()
- # make sure Qt really display the splash screen
- self.processEvents()
- # start the main app window
- self.mainWindow = MainWindow(self.clipboard(), self.args)
- self.mainWindow.show()
- if show_splash:
- # now kill the splashscreen
- self.splash.finish(self.mainWindow)
- log.debug(u'Splashscreen closed')
- # make sure Qt really display the splash screen
- self.processEvents()
- self.mainWindow.repaint()
- self.processEvents()
- if not has_run_wizard:
- self.mainWindow.firstTime()
- update_check = QtCore.QSettings().value(
- u'general/update check', QtCore.QVariant(True)).toBool()
- if update_check:
- VersionThread(self.mainWindow).start()
- Receiver.send_message(u'maindisplay_blank_check')
- self.mainWindow.appStartup()
- DelayStartThread(self.mainWindow).start()
- return self.exec_()
-
- def isAlreadyRunning(self):
- """
- Look to see if OpenLP is already running and ask if a 2nd copy
- is to be started.
- """
- self.sharedMemory = QtCore.QSharedMemory('OpenLP')
- if self.sharedMemory.attach():
- status = QtGui.QMessageBox.critical(None,
- UiStrings().Error, UiStrings().OpenLPStart,
- QtGui.QMessageBox.StandardButtons(
- QtGui.QMessageBox.Yes | QtGui.QMessageBox.No))
- if status == QtGui.QMessageBox.No:
- return True
- return False
- else:
- self.sharedMemory.create(1)
- return False
-
- def hookException(self, exctype, value, traceback):
- if not hasattr(self, u'mainWindow'):
- log.exception(''.join(format_exception(exctype, value, traceback)))
- return
- if not hasattr(self, u'exceptionForm'):
- self.exceptionForm = ExceptionForm(self.mainWindow)
- self.exceptionForm.exceptionTextEdit.setPlainText(
- ''.join(format_exception(exctype, value, traceback)))
- self.setNormalCursor()
- self.exceptionForm.exec_()
-
- def setBusyCursor(self):
- """
- Sets the Busy Cursor for the Application
- """
- self.setOverrideCursor(QtCore.Qt.BusyCursor)
- self.processEvents()
-
- def setNormalCursor(self):
- """
- Sets the Normal Cursor for the Application
- """
- self.restoreOverrideCursor()
-
- def event(self, event):
- """
- Enables direct file opening on OS X
- """
- if event.type() == QtCore.QEvent.FileOpen:
- file_name = event.file()
- log.debug(u'Got open file event for %s!', file_name)
- self.args.insert(0, unicode(file_name))
- return True
- else:
- return QtGui.QApplication.event(self, event)
-
-def main():
- """
- The main function which parses command line options and then runs
- the PyQt4 Application.
- """
- # Set up command line options.
- usage = 'Usage: %prog [options] [qt-options]'
- parser = OptionParser(usage=usage)
- parser.add_option('-e', '--no-error-form', dest='no_error_form',
- action='store_true', help='Disable the error notification form.')
- parser.add_option('-l', '--log-level', dest='loglevel',
- default='warning', metavar='LEVEL', help='Set logging to LEVEL '
- 'level. Valid values are "debug", "info", "warning".')
- parser.add_option('-p', '--portable', dest='portable',
- action='store_true', help='Specify if this should be run as a '
- 'portable app, off a USB flash drive (not implemented).')
- parser.add_option('-d', '--dev-version', dest='dev_version',
- action='store_true', help='Ignore the version file and pull the '
- 'version directly from Bazaar')
- parser.add_option('-s', '--style', dest='style',
- help='Set the Qt4 style (passed directly to Qt4).')
- # Set up logging
- log_path = AppLocation.get_directory(AppLocation.CacheDir)
- check_directory_exists(log_path)
- filename = os.path.join(log_path, u'openlp.log')
- logfile = logging.FileHandler(filename, u'w')
- logfile.setFormatter(logging.Formatter(
- u'%(asctime)s %(name)-55s %(levelname)-8s %(message)s'))
- log.addHandler(logfile)
- logging.addLevelName(15, u'Timer')
- # Parse command line options and deal with them.
- (options, args) = parser.parse_args()
- qt_args = []
- if options.loglevel.lower() in ['d', 'debug']:
- log.setLevel(logging.DEBUG)
- print 'Logging to:', filename
- elif options.loglevel.lower() in ['w', 'warning']:
- log.setLevel(logging.WARNING)
- else:
- log.setLevel(logging.INFO)
- if options.style:
- qt_args.extend(['-style', options.style])
- # Throw the rest of the arguments at Qt, just in case.
- qt_args.extend(args)
- # Initialise the resources
- qInitResources()
- # Now create and actually run the application.
- app = OpenLP(qt_args)
- # Instance check
- if app.isAlreadyRunning():
- sys.exit()
- app.setOrganizationName(u'OpenLP')
- app.setOrganizationDomain(u'openlp.org')
- app.setApplicationName(u'OpenLP')
- app.setApplicationVersion(get_application_version()[u'version'])
- # First time checks in settings
- if not QtCore.QSettings().value(u'general/has run wizard',
- QtCore.QVariant(False)).toBool():
- if not FirstTimeLanguageForm().exec_():
- # if cancel then stop processing
- sys.exit()
- if sys.platform == u'darwin':
- OpenLP.addLibraryPath(QtGui.QApplication.applicationDirPath()
- + "/qt4_plugins")
- # i18n Set Language
- language = LanguageManager.get_language()
- app_translator, default_translator = \
- LanguageManager.get_translator(language)
- if not app_translator.isEmpty():
- app.installTranslator(app_translator)
- if not default_translator.isEmpty():
- app.installTranslator(default_translator)
- else:
- log.debug(u'Could not find default_translator.')
- if not options.no_error_form:
- sys.excepthook = app.hookException
- sys.exit(app.run(qt_args))
if __name__ == u'__main__':
"""
diff --git a/openlp/core/__init__.py b/openlp/core/__init__.py
index e19b9a257..01d34956e 100644
--- a/openlp/core/__init__.py
+++ b/openlp/core/__init__.py
@@ -24,9 +24,269 @@
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
+
+__all__ = ('OpenLP', 'main')
+
+import os
+import sys
+import logging
+from optparse import OptionParser
+from traceback import format_exception
+
+from PyQt4 import QtCore, QtGui
+
+from openlp.core.lib import Receiver, check_directory_exists
+from openlp.core.lib.ui import UiStrings
+from openlp.core.resources import qInitResources
+from openlp.core.ui.mainwindow import MainWindow
+from openlp.core.ui.firsttimelanguageform import FirstTimeLanguageForm
+from openlp.core.ui.firsttimeform import FirstTimeForm
+from openlp.core.ui.exceptionform import ExceptionForm
+from openlp.core.ui import SplashScreen, ScreenList
+from openlp.core.utils import AppLocation, LanguageManager, VersionThread, \
+ get_application_version, DelayStartThread
+
+log = logging.getLogger()
+
+
"""
The :mod:`core` module provides all core application functions
All the core functions of the OpenLP application including the GUI, settings,
logging and a plugin framework are contained within the openlp.core module.
"""
+
+application_stylesheet = u"""
+QMainWindow::separator
+{
+ border: none;
+}
+
+QDockWidget::title
+{
+ border: 1px solid palette(dark);
+ padding-left: 5px;
+ padding-top: 2px;
+ margin: 1px 0;
+}
+
+QToolBar
+{
+ border: none;
+ margin: 0;
+ padding: 0;
+}
+"""
+
+
+class OpenLP(QtGui.QApplication):
+ """
+ The core application class. This class inherits from Qt's QApplication
+ class in order to provide the core of the application.
+ """
+
+ args = []
+
+ def exec_(self):
+ """
+ Override exec method to allow the shared memory to be released on exit
+ """
+ QtGui.QApplication.exec_()
+ self.sharedMemory.detach()
+
+ def run(self, args, testing=False):
+ """
+ Run the OpenLP application.
+ """
+ # On Windows, the args passed into the constructor are
+ # ignored. Not very handy, so set the ones we want to use.
+ self.args.extend(args)
+ # provide a listener for widgets to reqest a screen update.
+ QtCore.QObject.connect(Receiver.get_receiver(),
+ QtCore.SIGNAL(u'openlp_process_events'), self.processEvents)
+ QtCore.QObject.connect(Receiver.get_receiver(),
+ QtCore.SIGNAL(u'cursor_busy'), self.setBusyCursor)
+ QtCore.QObject.connect(Receiver.get_receiver(),
+ QtCore.SIGNAL(u'cursor_normal'), self.setNormalCursor)
+ # Decide how many screens we have and their size
+ screens = ScreenList(self.desktop())
+ # First time checks in settings
+ has_run_wizard = QtCore.QSettings().value(
+ u'general/has run wizard', QtCore.QVariant(False)).toBool()
+ if not has_run_wizard:
+ if FirstTimeForm(screens).exec_() == QtGui.QDialog.Accepted:
+ QtCore.QSettings().setValue(u'general/has run wizard',
+ QtCore.QVariant(True))
+ if os.name == u'nt':
+ self.setStyleSheet(application_stylesheet)
+ show_splash = QtCore.QSettings().value(
+ u'general/show splash', QtCore.QVariant(True)).toBool()
+ if show_splash:
+ self.splash = SplashScreen()
+ self.splash.show()
+ # make sure Qt really display the splash screen
+ self.processEvents()
+ # start the main app window
+ self.mainWindow = MainWindow(self.clipboard(), self.args)
+ self.mainWindow.show()
+ if show_splash:
+ # now kill the splashscreen
+ self.splash.finish(self.mainWindow)
+ log.debug(u'Splashscreen closed')
+ # make sure Qt really display the splash screen
+ self.processEvents()
+ self.mainWindow.repaint()
+ self.processEvents()
+ if not has_run_wizard:
+ self.mainWindow.firstTime()
+ update_check = QtCore.QSettings().value(
+ u'general/update check', QtCore.QVariant(True)).toBool()
+ if update_check:
+ VersionThread(self.mainWindow).start()
+ Receiver.send_message(u'maindisplay_blank_check')
+ self.mainWindow.appStartup()
+ DelayStartThread(self.mainWindow).start()
+ # Skip exec_() for gui tests
+ if not testing:
+ return self.exec_()
+
+ def isAlreadyRunning(self):
+ """
+ Look to see if OpenLP is already running and ask if a 2nd copy
+ is to be started.
+ """
+ self.sharedMemory = QtCore.QSharedMemory('OpenLP')
+ if self.sharedMemory.attach():
+ status = QtGui.QMessageBox.critical(None,
+ UiStrings().Error, UiStrings().OpenLPStart,
+ QtGui.QMessageBox.StandardButtons(
+ QtGui.QMessageBox.Yes | QtGui.QMessageBox.No))
+ if status == QtGui.QMessageBox.No:
+ return True
+ return False
+ else:
+ self.sharedMemory.create(1)
+ return False
+
+ def hookException(self, exctype, value, traceback):
+ if not hasattr(self, u'mainWindow'):
+ log.exception(''.join(format_exception(exctype, value, traceback)))
+ return
+ if not hasattr(self, u'exceptionForm'):
+ self.exceptionForm = ExceptionForm(self.mainWindow)
+ self.exceptionForm.exceptionTextEdit.setPlainText(
+ ''.join(format_exception(exctype, value, traceback)))
+ self.setNormalCursor()
+ self.exceptionForm.exec_()
+
+ def setBusyCursor(self):
+ """
+ Sets the Busy Cursor for the Application
+ """
+ self.setOverrideCursor(QtCore.Qt.BusyCursor)
+ self.processEvents()
+
+ def setNormalCursor(self):
+ """
+ Sets the Normal Cursor for the Application
+ """
+ self.restoreOverrideCursor()
+
+ def event(self, event):
+ """
+ Enables direct file opening on OS X
+ """
+ if event.type() == QtCore.QEvent.FileOpen:
+ file_name = event.file()
+ log.debug(u'Got open file event for %s!', file_name)
+ self.args.insert(0, unicode(file_name))
+ return True
+ else:
+ return QtGui.QApplication.event(self, event)
+
+
+def main(args=None):
+ """
+ The main function which parses command line options and then runs
+ the PyQt4 Application.
+ """
+ # Set up command line options.
+ usage = 'Usage: %prog [options] [qt-options]'
+ parser = OptionParser(usage=usage)
+ parser.add_option('-e', '--no-error-form', dest='no_error_form',
+ action='store_true', help='Disable the error notification form.')
+ parser.add_option('-l', '--log-level', dest='loglevel',
+ default='warning', metavar='LEVEL', help='Set logging to LEVEL '
+ 'level. Valid values are "debug", "info", "warning".')
+ parser.add_option('-p', '--portable', dest='portable',
+ action='store_true', help='Specify if this should be run as a '
+ 'portable app, off a USB flash drive (not implemented).')
+ parser.add_option('-d', '--dev-version', dest='dev_version',
+ action='store_true', help='Ignore the version file and pull the '
+ 'version directly from Bazaar')
+ parser.add_option('-s', '--style', dest='style',
+ help='Set the Qt4 style (passed directly to Qt4).')
+ parser.add_option('--testing', dest='testing',
+ action='store_true', help='Run by testing framework')
+ # Set up logging
+ log_path = AppLocation.get_directory(AppLocation.CacheDir)
+ check_directory_exists(log_path)
+ filename = os.path.join(log_path, u'openlp.log')
+ logfile = logging.FileHandler(filename, u'w')
+ logfile.setFormatter(logging.Formatter(
+ u'%(asctime)s %(name)-55s %(levelname)-8s %(message)s'))
+ log.addHandler(logfile)
+ logging.addLevelName(15, u'Timer')
+ # Parse command line options and deal with them.
+ # Use args supplied programatically if possible.
+ (options, args) = parser.parse_args(args) if args else parser.parse_args()
+ qt_args = []
+ if options.loglevel.lower() in ['d', 'debug']:
+ log.setLevel(logging.DEBUG)
+ print 'Logging to:', filename
+ elif options.loglevel.lower() in ['w', 'warning']:
+ log.setLevel(logging.WARNING)
+ else:
+ log.setLevel(logging.INFO)
+ if options.style:
+ qt_args.extend(['-style', options.style])
+ # Throw the rest of the arguments at Qt, just in case.
+ qt_args.extend(args)
+ # Initialise the resources
+ qInitResources()
+ # Now create and actually run the application.
+ app = OpenLP(qt_args)
+ app.setOrganizationName(u'OpenLP')
+ app.setOrganizationDomain(u'openlp.org')
+ app.setApplicationName(u'OpenLP')
+ app.setApplicationVersion(get_application_version()[u'version'])
+ # Instance check
+ if not options.testing:
+ # Instance check
+ if app.isAlreadyRunning():
+ sys.exit()
+ # First time checks in settings
+ if not QtCore.QSettings().value(u'general/has run wizard',
+ QtCore.QVariant(False)).toBool():
+ if not FirstTimeLanguageForm().exec_():
+ # if cancel then stop processing
+ sys.exit()
+ # i18n Set Language
+ language = LanguageManager.get_language()
+ app_translator, default_translator = \
+ LanguageManager.get_translator(language)
+ if not app_translator.isEmpty():
+ app.installTranslator(app_translator)
+ if not default_translator.isEmpty():
+ app.installTranslator(default_translator)
+ else:
+ log.debug(u'Could not find default_translator.')
+ if not options.no_error_form:
+ sys.excepthook = app.hookException
+ # Do not run method app.exec_() when running gui tests
+ if options.testing:
+ app.run(qt_args, testing=True)
+ # For gui tests we need access to window intances and their components
+ return app
+ else:
+ sys.exit(app.run(qt_args))
diff --git a/openlp/core/lib/mediamanageritem.py b/openlp/core/lib/mediamanageritem.py
index a721fabf6..f21d8df50 100644
--- a/openlp/core/lib/mediamanageritem.py
+++ b/openlp/core/lib/mediamanageritem.py
@@ -377,7 +377,7 @@ class MediaManagerItem(QtGui.QWidget):
"""
names = []
for count in range(0, self.listView.count()):
- names.append(self.listView.item(count).text())
+ names.append(unicode(self.listView.item(count).text()))
newFiles = []
duplicatesFound = False
for file in files:
@@ -396,7 +396,7 @@ class MediaManagerItem(QtGui.QWidget):
critical_error_message_box(
UiStrings().Duplicate,
unicode(translate('OpenLP.MediaManagerItem',
- 'Duplicate files found on import and ignored.')))
+ 'Duplicate files were found on import and were ignored.')))
def contextMenu(self, point):
item = self.listView.itemAt(point)
diff --git a/openlp/core/lib/renderer.py b/openlp/core/lib/renderer.py
index 8c63facb8..185d74878 100644
--- a/openlp/core/lib/renderer.py
+++ b/openlp/core/lib/renderer.py
@@ -233,49 +233,43 @@ class Renderer(object):
len(pages) > 1 and u'[---]' in text:
pages = []
while True:
- # Check if the first two potential virtual slides will fit
- # (as a whole) on one slide.
- html_text = expand_tags(
- u'\n'.join(text.split(u'\n[---]\n', 2)[:-1]))
+ slides = text.split(u'\n[---]\n', 2)
+ # If there are (at least) two occurrences of [---] we use
+ # the first two slides (and neglect the last for now).
+ if len(slides) == 3:
+ html_text = expand_tags(u'\n'.join(slides[:2]))
+ # We check both slides to determine if the virtual break is
+ # needed (there is only one virtual break).
+ else:
+ html_text = expand_tags(u'\n'.join(slides))
html_text = html_text.replace(u'\n', u'
')
if self._text_fits_on_slide(html_text):
# The first two virtual slides fit (as a whole) on one
- # slide. Replace the occurrences of [---].
- text = text.replace(u'\n[---]', u'', 2)
+ # slide. Replace the first occurrence of [---].
+ text = text.replace(u'\n[---]', u'', 1)
else:
- # The first two virtual slides did not fit as a whole.
- # Check if the first virtual slide will fit.
- html_text = expand_tags(text.split(u'\n[---]\n', 1)[1])
- html_text = html_text.replace(u'\n', u'
')
- if self._text_fits_on_slide(html_text):
- # The first virtual slide fits, so remove it.
- text = text.replace(u'\n[---]', u'', 1)
+ # The first virtual slide fits, which means we have to
+ # render the first virtual slide.
+ text_contains_break = u'[---]' in text
+ if text_contains_break:
+ text_to_render, text = text.split(u'\n[---]\n', 1)
else:
- # The first virtual slide does not fit, which means
- # we have to render the first virtual slide.
- text_contains_break = u'[---]' in text
- if text_contains_break:
- html_text, text = text.split(u'\n[---]\n', 1)
+ text_to_render = text
+ text = u''
+ lines = text_to_render.strip(u'\n').split(u'\n')
+ slides = self._paginate_slide(lines, line_end)
+ if len(slides) > 1 and text:
+ # Add all slides apart from the last one the list.
+ pages.extend(slides[:-1])
+ if text_contains_break:
+ text = slides[-1] + u'\n[---]\n' + text
else:
- html_text = text
- text = u''
- lines = expand_tags(html_text)
- lines = lines.strip(u'\n').split(u'\n')
- slides = self._paginate_slide(lines, line_end)
- if len(slides) > 1 and text:
- # Add all slides apart from the last one the
- # list.
- pages.extend(slides[:-1])
- if text_contains_break:
- text = slides[-1] + u'\n[---]\n' + text
- else:
- text = slides[-1] + u'\n'+ text
- text = text.replace(u'
', u'\n')
- else:
- pages.extend(slides)
+ text = slides[-1] + u'\n'+ text
+ text = text.replace(u'
', u'\n')
+ else:
+ pages.extend(slides)
if u'[---]' not in text:
- lines = expand_tags(text)
- lines = lines.strip(u'\n').split(u'\n')
+ lines = text.strip(u'\n').split(u'\n')
pages.extend(self._paginate_slide(lines, line_end))
break
new_pages = []
diff --git a/openlp/core/ui/mainwindow.py b/openlp/core/ui/mainwindow.py
index 1b69e481f..e77112644 100644
--- a/openlp/core/ui/mainwindow.py
+++ b/openlp/core/ui/mainwindow.py
@@ -791,6 +791,9 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
self.themeManagerContents.loadThemes(True)
Receiver.send_message(u'theme_update_global',
self.themeManagerContents.global_theme)
+ # Check if any Bibles downloaded. If there are, they will be
+ # processed.
+ Receiver.send_message(u'bibles_load_list', True)
def blankCheck(self):
"""
diff --git a/openlp/core/ui/servicemanager.py b/openlp/core/ui/servicemanager.py
index ad1161e0d..20edab792 100644
--- a/openlp/core/ui/servicemanager.py
+++ b/openlp/core/ui/servicemanager.py
@@ -586,8 +586,8 @@ class ServiceManager(QtGui.QWidget):
fileTo = None
try:
zip = zipfile.ZipFile(fileName)
- for file in zip.namelist():
- ucsfile = file_is_unicode(file)
+ for zipinfo in zip.infolist():
+ ucsfile = file_is_unicode(zipinfo.filename)
if not ucsfile:
critical_error_message_box(
message=translate('OpenLP.ServiceManager',
@@ -595,14 +595,11 @@ class ServiceManager(QtGui.QWidget):
'The content encoding is not UTF-8.'))
continue
osfile = unicode(QtCore.QDir.toNativeSeparators(ucsfile))
- filePath = os.path.join(self.servicePath,
- os.path.split(osfile)[1])
- fileTo = open(filePath, u'wb')
- fileTo.write(zip.read(file))
- fileTo.flush()
- fileTo.close()
- if filePath.endswith(u'osd'):
- p_file = filePath
+ filename_only = os.path.split(osfile)[1]
+ zipinfo.filename = filename_only
+ zip.extract(zipinfo, self.servicePath)
+ if filename_only.endswith(u'osd'):
+ p_file = os.path.join(self.servicePath, filename_only)
if 'p_file' in locals():
Receiver.send_message(u'cursor_busy')
fileTo = open(p_file, u'r')
diff --git a/openlp/plugins/bibles/lib/http.py b/openlp/plugins/bibles/lib/http.py
index 290da104c..2d8e16c4c 100644
--- a/openlp/plugins/bibles/lib/http.py
+++ b/openlp/plugins/bibles/lib/http.py
@@ -218,7 +218,7 @@ class BSExtract(object):
send_error_message(u'parse')
return None
content = content.find(u'div').findAll(u'div')
- verse_number = re.compile(r'v(\d{1,2})(\d{3})(\d{3}) verse')
+ verse_number = re.compile(r'v(\d{1,2})(\d{3})(\d{3}) verse.*')
verses = {}
for verse in content:
Receiver.send_message(u'openlp_process_events')
diff --git a/openlp/plugins/bibles/lib/mediaitem.py b/openlp/plugins/bibles/lib/mediaitem.py
index 91009424c..9083b18a2 100644
--- a/openlp/plugins/bibles/lib/mediaitem.py
+++ b/openlp/plugins/bibles/lib/mediaitem.py
@@ -391,10 +391,13 @@ class BibleMediaItem(MediaManagerItem):
elif len(bibles):
self.initialiseAdvancedBible(bibles[0])
- def reloadBibles(self):
+ def reloadBibles(self, process=False):
log.debug(u'Reloading Bibles')
self.plugin.manager.reload_bibles()
self.loadBibles()
+ # If called from first time wizard re-run, process any new bibles.
+ if process:
+ self.plugin.appStartup()
self.updateAutoCompleter()
def initialiseAdvancedBible(self, bible):
diff --git a/openlp/plugins/songs/lib/__init__.py b/openlp/plugins/songs/lib/__init__.py
index e2996ff8f..1b0ca316e 100644
--- a/openlp/plugins/songs/lib/__init__.py
+++ b/openlp/plugins/songs/lib/__init__.py
@@ -184,10 +184,11 @@ class VerseType(object):
verse_index = VerseType.from_translated_string(verse_name)
if verse_index is None:
verse_index = VerseType.from_string(verse_name)
- if verse_index is None:
- verse_index = VerseType.from_translated_tag(verse_name)
- if verse_index is None:
- verse_index = VerseType.from_tag(verse_name)
+ elif len(verse_name) == 1:
+ if verse_index is None:
+ verse_index = VerseType.from_translated_tag(verse_name)
+ if verse_index is None:
+ verse_index = VerseType.from_tag(verse_name)
return verse_index
def retrieve_windows_encoding(recommendation=None):
diff --git a/openlp/plugins/songs/lib/opensongimport.py b/openlp/plugins/songs/lib/opensongimport.py
index 7fca88262..632170807 100644
--- a/openlp/plugins/songs/lib/opensongimport.py
+++ b/openlp/plugins/songs/lib/opensongimport.py
@@ -190,7 +190,10 @@ class OpenSongImport(SongImport):
# the verse tag
verse_tag = content
verse_num = u'1'
- verse_index = VerseType.from_loose_input(verse_tag)
+ if len(verse_tag) == 0:
+ verse_index = 0
+ else:
+ verse_index = VerseType.from_loose_input(verse_tag)
verse_tag = VerseType.Tags[verse_index]
inst = 1
if [verse_tag, verse_num, inst] in our_verse_order \
diff --git a/openlp/plugins/songs/lib/songshowplusimport.py b/openlp/plugins/songs/lib/songshowplusimport.py
index c50df8752..591f71c10 100644
--- a/openlp/plugins/songs/lib/songshowplusimport.py
+++ b/openlp/plugins/songs/lib/songshowplusimport.py
@@ -103,6 +103,8 @@ class SongShowPlusImport(SongImport):
return
self.import_wizard.progressBar.setMaximum(len(self.import_source))
for file in self.import_source:
+ if self.stop_import_flag:
+ return
self.sspVerseOrderList = []
otherCount = 0
otherList = {}
diff --git a/openlp/plugins/songs/lib/wowimport.py b/openlp/plugins/songs/lib/wowimport.py
index e2a5820a5..4cfb81cb1 100644
--- a/openlp/plugins/songs/lib/wowimport.py
+++ b/openlp/plugins/songs/lib/wowimport.py
@@ -105,6 +105,8 @@ class WowImport(SongImport):
if isinstance(self.import_source, list):
self.import_wizard.progressBar.setMaximum(len(self.import_source))
for file in self.import_source:
+ if self.stop_import_flag:
+ return
file_name = os.path.split(file)[1]
# Get the song title
self.title = file_name.rpartition(u'.')[0]
diff --git a/scripts/check_dependencies.py b/scripts/check_dependencies.py
index 5f2e4c148..14d27fb81 100755
--- a/scripts/check_dependencies.py
+++ b/scripts/check_dependencies.py
@@ -80,6 +80,7 @@ OPTIONAL_MODULES = [
('sqlite', ' (SQLite 2 support)'),
('MySQLdb', ' (MySQL support)'),
('psycopg2', ' (PostgreSQL support)'),
+ ('pytest', ' (testing framework)'),
]
w = sys.stdout.write
diff --git a/testing/conftest.py b/testing/conftest.py
new file mode 100644
index 000000000..f38018c17
--- /dev/null
+++ b/testing/conftest.py
@@ -0,0 +1,45 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
+
+###############################################################################
+# OpenLP - Open Source Lyrics Projection #
+# --------------------------------------------------------------------------- #
+# Copyright (c) 2008-2011 Raoul Snyman #
+# Portions copyright (c) 2008-2011 Tim Bentley, Gerald Britton, Jonathan #
+# Corwin, Michael Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, #
+# Armin Köhler, Joshua Millar, Stevan Pettit, Andreas Preikschat, Mattias #
+# Põldaru, Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, #
+# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund #
+# --------------------------------------------------------------------------- #
+# This program is free software; you can redistribute it and/or modify it #
+# under the terms of the GNU General Public License as published by the Free #
+# Software Foundation; version 2 of the License. #
+# #
+# This program is distributed in the hope that it will be useful, but WITHOUT #
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
+# more details. #
+# #
+# You should have received a copy of the GNU General Public License along #
+# with this program; if not, write to the Free Software Foundation, Inc., 59 #
+# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
+###############################################################################
+
+"""
+Configuration file for pytest framework.
+"""
+
+from openlp.core import main as openlp_main
+
+
+# Test function argument to make openlp gui instance persistent for all tests.
+# All test cases have to access the same instance. To allow create multiple
+# instances it would be necessary use diffrent configuraion and data files.
+# Created instance will use your OpenLP settings.
+def pytest_funcarg__openlpapp(request):
+ def setup():
+ return openlp_main(['--testing'])
+ def teardown(app):
+ pass
+ return request.cached_setup(setup=setup, teardown=teardown, scope='session')
diff --git a/testing/run.py b/testing/run.py
new file mode 100755
index 000000000..1f0f54858
--- /dev/null
+++ b/testing/run.py
@@ -0,0 +1,59 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
+
+###############################################################################
+# OpenLP - Open Source Lyrics Projection #
+# --------------------------------------------------------------------------- #
+# Copyright (c) 2008-2011 Raoul Snyman #
+# Portions copyright (c) 2008-2011 Tim Bentley, Gerald Britton, Jonathan #
+# Corwin, Michael Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, #
+# Armin Köhler, Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias #
+# Põldaru, Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, #
+# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund #
+# --------------------------------------------------------------------------- #
+# This program is free software; you can redistribute it and/or modify it #
+# under the terms of the GNU General Public License as published by the Free #
+# Software Foundation; version 2 of the License. #
+# #
+# This program is distributed in the hope that it will be useful, but WITHOUT #
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
+# more details. #
+# #
+# You should have received a copy of the GNU General Public License along #
+# with this program; if not, write to the Free Software Foundation, Inc., 59 #
+# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
+###############################################################################
+
+"""
+This script is used to run set of automated tests of OpenLP. To start tests,
+simply run this script::
+
+ @:~$ ./run.py
+
+"""
+
+import os.path
+import sys
+
+TESTS_PATH = os.path.dirname(os.path.abspath(__file__))
+SRC_PATH = os.path.join(TESTS_PATH, '..')
+
+PYTEST_OPTIONS = [TESTS_PATH]
+
+# Extend python PATH with openlp source
+sys.path.insert(0, SRC_PATH)
+
+# Python testing framework
+# http://pytest.org
+import pytest
+
+
+def main():
+ print 'pytest options:', PYTEST_OPTIONS
+ pytest.main(PYTEST_OPTIONS)
+
+
+if __name__ == u'__main__':
+ main()
diff --git a/testing/test_app.py b/testing/test_app.py
new file mode 100644
index 000000000..00cd744ba
--- /dev/null
+++ b/testing/test_app.py
@@ -0,0 +1,36 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
+
+###############################################################################
+# OpenLP - Open Source Lyrics Projection #
+# --------------------------------------------------------------------------- #
+# Copyright (c) 2008-2011 Raoul Snyman #
+# Portions copyright (c) 2008-2011 Tim Bentley, Gerald Britton, Jonathan #
+# Corwin, Michael Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, #
+# Armin Köhler, Joshua Millar, Stevan Pettit, Andreas Preikschat, Mattias #
+# Põldaru, Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, #
+# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund #
+# --------------------------------------------------------------------------- #
+# This program is free software; you can redistribute it and/or modify it #
+# under the terms of the GNU General Public License as published by the Free #
+# Software Foundation; version 2 of the License. #
+# #
+# This program is distributed in the hope that it will be useful, but WITHOUT #
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
+# more details. #
+# #
+# You should have received a copy of the GNU General Public License along #
+# with this program; if not, write to the Free Software Foundation, Inc., 59 #
+# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
+###############################################################################
+
+from openlp.core import OpenLP
+from openlp.core.ui.mainwindow import MainWindow
+
+
+def test_start_app(openlpapp):
+ assert type(openlpapp) == OpenLP
+ assert type(openlpapp.mainWindow) == MainWindow
+ assert unicode(openlpapp.mainWindow.windowTitle()) == u'OpenLP 2.0'