Merge and fixes

This commit is contained in:
Tim Bentley 2013-02-16 10:40:05 +00:00
commit 616684d9ad
20 changed files with 413 additions and 50 deletions

View File

@ -30,6 +30,7 @@
The :mod:`lib` module contains most of the components and libraries that make
OpenLP work.
"""
from distutils.version import LooseVersion
import logging
import os
@ -366,23 +367,23 @@ def create_separated_list(stringlist):
``stringlist``
List of unicode strings
"""
if Qt.PYQT_VERSION_STR >= u'4.9' and Qt.qVersion() >= u'4.8':
if LooseVersion(Qt.PYQT_VERSION_STR) >= LooseVersion(u'4.9') and \
LooseVersion(Qt.qVersion()) >= LooseVersion(u'4.8'):
return QtCore.QLocale().createSeparatedList(stringlist)
if not stringlist:
return u''
elif len(stringlist) == 1:
return stringlist[0]
elif len(stringlist) == 2:
return translate('OpenLP.core.lib', '%1 and %2',
return translate('OpenLP.core.lib', '%s and %s',
'Locale list separator: 2 items') % (stringlist[0], stringlist[1])
else:
merged = translate('OpenLP.core.lib', '%1, and %2',
merged = translate('OpenLP.core.lib', '%s, and %s',
u'Locale list separator: end') % (stringlist[-2], stringlist[-1])
for index in reversed(range(1, len(stringlist) - 2)):
merged = translate('OpenLP.core.lib', '%1, %2',
u'Locale list separator: middle') % (stringlist[index], merged)
return translate('OpenLP.core.lib', '%1, %2',
u'Locale list separator: start') % (stringlist[0], merged)
merged = translate('OpenLP.core.lib', '%s, %s',
u'Locale list separator: middle') % (stringlist[index], merged)
return translate('OpenLP.core.lib', '%s, %s', u'Locale list separator: start') % (stringlist[0], merged)
from registry import Registry

View File

@ -34,18 +34,18 @@ from PyQt4 import QtGui
from filerenamedialog import Ui_FileRenameDialog
from openlp.core.lib import translate
from openlp.core.lib import translate, Registry
class FileRenameForm(QtGui.QDialog, Ui_FileRenameDialog):
"""
The file rename dialog
"""
def __init__(self, parent):
def __init__(self):
"""
Constructor
"""
QtGui.QDialog.__init__(self, parent)
QtGui.QDialog.__init__(self, self.main_window)
self.setupUi(self)
def exec_(self, copy=False):
@ -56,4 +56,15 @@ class FileRenameForm(QtGui.QDialog, Ui_FileRenameDialog):
self.setWindowTitle(translate('OpenLP.FileRenameForm', 'File Copy'))
else:
self.setWindowTitle(translate('OpenLP.FileRenameForm', 'File Rename'))
self.fileNameEdit.setFocus()
return QtGui.QDialog.exec_(self)
def _get_main_window(self):
"""
Adds the main window to the class dynamically
"""
if not hasattr(self, u'_main_window'):
self._main_window = Registry().get(u'main_window')
return self._main_window
main_window = property(_get_main_window)

View File

@ -62,7 +62,7 @@ class ThemeManager(QtGui.QWidget):
Registry().register(u'theme_manager', self)
self.settingsSection = u'themes'
self.themeForm = ThemeForm(self)
self.fileRenameForm = FileRenameForm(self)
self.fileRenameForm = FileRenameForm()
# start with the layout
self.layout = QtGui.QVBoxLayout(self)
self.layout.setSpacing(0)

View File

@ -198,8 +198,10 @@ class AlertForm(QtGui.QDialog, Ui_AlertDialog):
QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.No | QtGui.QMessageBox.Yes)) == QtGui.QMessageBox.No:
self.parameter_edit.setFocus()
return False
text = text.replace(u'<>', self.parameter_edit.text())
self.plugin.alerts_manager.display_alert(text)
self.plugin.alertsmanager.display_alert(text)
return True
def on_current_row_changed(self, row):

View File

@ -37,8 +37,10 @@ from PyQt4 import QtCore
from openlp.core.lib import Registry, translate
log = logging.getLogger(__name__)
class AlertsManager(QtCore.QObject):
"""
AlertsManager manages the settings of Alerts.
@ -107,16 +109,6 @@ class AlertsManager(QtCore.QObject):
self.timer_id = 0
self.generate_alert()
def _get_main_window(self):
"""
Adds the main window to the class dynamically
"""
if not hasattr(self, u'_main_window'):
self._main_window = Registry().get(u'main_window')
return self._main_window
main_window = property(_get_main_window)
def _get_live_controller(self):
"""
Adds the live controller to the class dynamically
@ -126,3 +118,13 @@ class AlertsManager(QtCore.QObject):
return self._live_controller
live_controller = property(_get_live_controller)
def _get_main_window(self):
"""
Adds the main window to the class dynamically
"""
if not hasattr(self, u'_main_window'):
self._main_window = Registry().get(u'main_window')
return self._main_window
main_window = property(_get_main_window)

View File

@ -27,7 +27,7 @@
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
from PyQt4 import QtCore, QtGui
from PyQt4 import QtGui
import logging
@ -98,4 +98,14 @@ class ImagePlugin(Plugin):
last part of saving the config.
"""
background = QtGui.QColor(Settings().value(self.settingsSection + u'/background color'))
self.liveController.imageManager.update_images_border(ImageSource.ImagePlugin, background)
self.image_manager.update_images_border(ImageSource.ImagePlugin, background)
def _get_image_manager(self):
"""
Adds the image manager to the class dynamically
"""
if not hasattr(self, u'_image_manager'):
self._image_manager = Registry().get(u'image_manager')
return self._image_manager
image_manager = property(_get_image_manager)

View File

@ -124,6 +124,7 @@ from PyQt4 import QtCore, QtNetwork
from mako.template import Template
from openlp.core.lib import Registry, Settings, PluginStatus, StringContent
from openlp.core.utils import AppLocation, translate
log = logging.getLogger(__name__)
@ -250,12 +251,11 @@ class HttpConnection(object):
def _get_service_items(self):
service_items = []
service_manager = self.parent.plugin.serviceManager
if self.parent.current_item:
current_unique_identifier = self.parent.current_item.unique_identifier
else:
current_unique_identifier = None
for item in service_manager.serviceItems:
for item in self.service_manager.serviceItems:
service_item = item[u'service_item']
service_items.append({
u'id': unicode(service_item.unique_identifier),
@ -386,13 +386,13 @@ class HttpConnection(object):
Poll OpenLP to determine the current slide number and item name.
"""
result = {
u'service': self.parent.plugin.serviceManager.service_id,
u'service': self.service_manager.service_id,
u'slide': self.parent.current_slide or 0,
u'item': self.parent.current_item.unique_identifier if self.parent.current_item else u'',
u'twelve':Settings().value(u'remotes/twelve hour'),
u'blank': self.parent.plugin.liveController.blankScreen.isChecked(),
u'theme': self.parent.plugin.liveController.themeScreen.isChecked(),
u'display': self.parent.plugin.liveController.desktopScreen.isChecked()
u'blank': self.live_controller.blankScreen.isChecked(),
u'theme': self.live_controller.themeScreen.isChecked(),
u'display': self.live_controller.desktopScreen.isChecked()
}
return HttpResponse(json.dumps({u'results': result}),
{u'Content-Type': u'application/json'})
@ -412,7 +412,7 @@ class HttpConnection(object):
"""
Send an alert.
"""
plugin = self.parent.plugin.pluginManager.get_plugin_by_name("alerts")
plugin = self.plugin_manager.get_plugin_by_name("alerts")
if plugin.status == PluginStatus.Active:
try:
text = json.loads(self.url_params[u'data'][0])[u'request'][u'text']
@ -504,7 +504,7 @@ class HttpConnection(object):
"""
if action == u'search':
searches = []
for plugin in self.parent.plugin.pluginManager.plugins:
for plugin in self.plugin_manager.plugins:
if plugin.status == PluginStatus.Active and plugin.mediaItem and plugin.mediaItem.hasSearch:
searches.append([plugin.name, unicode(plugin.textStrings[StringContent.Name][u'plural'])])
return HttpResponse(
@ -523,7 +523,7 @@ class HttpConnection(object):
except KeyError, ValueError:
return HttpResponse(code=u'400 Bad Request')
text = urllib.unquote(text)
plugin = self.parent.plugin.pluginManager.get_plugin_by_name(type)
plugin = self.plugin_manager.get_plugin_by_name(type)
if plugin.status == PluginStatus.Active and plugin.mediaItem and plugin.mediaItem.hasSearch:
results = plugin.mediaItem.search(text, False)
else:
@ -539,7 +539,7 @@ class HttpConnection(object):
id = json.loads(self.url_params[u'data'][0])[u'request'][u'id']
except KeyError, ValueError:
return HttpResponse(code=u'400 Bad Request')
plugin = self.parent.plugin.pluginManager.get_plugin_by_name(type)
plugin = self.plugin_manager.get_plugin_by_name(type)
if plugin.status == PluginStatus.Active and plugin.mediaItem:
plugin.mediaItem.goLive(id, remote=True)
return HttpResponse(code=u'200 OK')
@ -552,7 +552,7 @@ class HttpConnection(object):
id = json.loads(self.url_params[u'data'][0])[u'request'][u'id']
except KeyError, ValueError:
return HttpResponse(code=u'400 Bad Request')
plugin = self.parent.plugin.pluginManager.get_plugin_by_name(type)
plugin = self.plugin_manager.get_plugin_by_name(type)
if plugin.status == PluginStatus.Active and plugin.mediaItem:
item_id = plugin.mediaItem.createItemFromId(id)
plugin.mediaItem.addToService(item_id, remote=True)
@ -583,3 +583,33 @@ class HttpConnection(object):
self.socket.close()
self.socket = None
self.parent.close_connection(self)
def _get_service_manager(self):
"""
Adds the service manager to the class dynamically
"""
if not hasattr(self, u'_service_manager'):
self._service_manager = Registry().get(u'service_manager')
return self._service_manager
service_manager = property(_get_service_manager)
def _get_live_controller(self):
"""
Adds the live controller to the class dynamically
"""
if not hasattr(self, u'_live_controller'):
self._live_controller = Registry().get(u'live_controller')
return self._live_controller
live_controller = property(_get_live_controller)
def _get_plugin_manager(self):
"""
Adds the plugin manager to the class dynamically
"""
if not hasattr(self, u'_plugin_manager'):
self._plugin_manager = Registry().get(u'plugin_manager')
return self._plugin_manager
plugin_manager = property(_get_plugin_manager)

View File

@ -116,6 +116,23 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
self.findVerseSplit = re.compile(u'---\[\]---\n', re.UNICODE)
self.whitespace = re.compile(r'\W+', re.UNICODE)
def keyPressEvent(self, event):
"""
Reimplement the keyPressEvent to react on Return/Enter keys. When some combo boxes have focus we do not want
dialog's default action be triggered but instead our own.
``event``
A QtGui.QKeyEvent event.
"""
if event.key() in (QtCore.Qt.Key_Enter, QtCore.Qt.Key_Return):
if self.authorsComboBox.hasFocus() and self.authorsComboBox.currentText():
self.onAuthorAddButtonClicked()
return
if self.topicsComboBox.hasFocus() and self.topicsComboBox.currentText():
self.onTopicAddButtonClicked()
return
QtGui.QDialog.keyPressEvent(self, event)
def initialise(self):
"""
Set up the form for when it is displayed.

View File

@ -40,7 +40,13 @@ import os
import sys
from distutils.version import LooseVersion
is_win = sys.platform.startswith('win')
# If we try to import uno before nose this will greate a warning. Just try to import nose first to supress the warning.
try:
import nose
except ImportError:
pass
IS_WIN = sys.platform.startswith('win')
VERS = {
'Python': '2.6',
@ -48,7 +54,7 @@ VERS = {
'Qt4': '4.6',
'sqlalchemy': '0.5',
# pyenchant 1.6 required on Windows
'enchant': '1.6' if is_win else '1.3'
'enchant': '1.6' if IS_WIN else '1.3'
}
# pywin32
@ -84,7 +90,7 @@ OPTIONAL_MODULES = [
('sqlite', ' (SQLite 2 support)'),
('MySQLdb', ' (MySQL support)'),
('psycopg2', ' (PostgreSQL support)'),
('pytest', ' (testing framework)'),
('nose', ' (testing framework)'),
]
w = sys.stdout.write
@ -176,7 +182,7 @@ def main():
for m in OPTIONAL_MODULES:
check_module(m[0], text=m[1])
if is_win:
if IS_WIN:
print('Checking for Windows specific modules...')
for m in WIN32_MODULES:
check_module(m)

View File

@ -0,0 +1,8 @@
import sip
sip.setapi(u'QDate', 2)
sip.setapi(u'QDateTime', 2)
sip.setapi(u'QString', 2)
sip.setapi(u'QTextStream', 2)
sip.setapi(u'QTime', 2)
sip.setapi(u'QUrl', 2)
sip.setapi(u'QVariant', 2)

View File

@ -0,0 +1,50 @@
"""
Package to test the openlp.core.ui package.
"""
import os
from unittest import TestCase
from PyQt4 import QtGui
from openlp.core.lib import Registry, ImageManager, ScreenList
TEST_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), u'..', u'..', u'resources'))
class TestImageManager(TestCase):
def setUp(self):
"""
Create the UI
"""
Registry.create()
self.app = QtGui.QApplication([])
ScreenList.create(self.app.desktop())
self.image_manager = ImageManager()
def tearDown(self):
"""
Delete all the C++ objects at the end so that we don't have a segfault
"""
del self.app
def basic_image_manager_test(self):
"""
Test the Image Manager setup basic functionality
"""
# GIVEN: the an image add to the image manager
self.image_manager.add_image(TEST_PATH, u'church.jpg', None)
# WHEN the image is retrieved
image = self.image_manager.get_image(TEST_PATH, u'church.jpg')
# THEN returned record is a type of image
self.assertEqual(isinstance(image, QtGui.QImage), True, u'The returned object should be a QImage')
# WHEN the image is retrieved has not been loaded
# THEN a KeyError is thrown
with self.assertRaises(KeyError) as context:
self.image_manager.get_image(TEST_PATH, u'church1.jpg')
self.assertNotEquals(context.exception[0], u'', u'KeyError exception should have been thrown for missing image')

View File

@ -7,7 +7,7 @@ from datetime import datetime, timedelta
from mock import MagicMock, patch
from openlp.core.lib import str_to_bool, translate, check_directory_exists, get_text_file_string, build_icon, \
image_to_byte, check_item_selected, validate_thumb
image_to_byte, check_item_selected, validate_thumb, create_separated_list
class TestLib(TestCase):
@ -308,14 +308,14 @@ class TestLib(TestCase):
file_path = u'path/to/file'
thumb_path = u'path/to/thumb'
mocked_os.path.exists.return_value = False
# WHEN: we run the validate_thumb() function
result = validate_thumb(file_path, thumb_path)
# THEN: we should have called a few functions, and the result should be False
mocked_os.path.exists.assert_called_with(thumb_path)
assert result is False, u'The result should be False'
def validate_thumb_file_exists_and_newer_test(self):
"""
Test the validate_thumb() function when the thumbnail exists and has a newer timestamp than the file
@ -350,7 +350,7 @@ class TestLib(TestCase):
thumb_mocked_stat.st_mtime = datetime.now() - timedelta(seconds=10)
mocked_os.path.exists.return_value = True
mocked_os.stat.side_effect = lambda fname: file_mocked_stat if fname == file_path else thumb_mocked_stat
# WHEN: we run the validate_thumb() function
result = validate_thumb(file_path, thumb_path)
@ -359,3 +359,90 @@ class TestLib(TestCase):
mocked_os.stat.assert_any_call(file_path)
mocked_os.stat.assert_any_call(thumb_path)
assert result is False, u'The result should be False'
def create_separated_list_qlocate_test(self):
"""
Test the create_separated_list function using the Qt provided method.
"""
with patch(u'openlp.core.lib.Qt') as mocked_qt, \
patch(u'openlp.core.lib.QtCore.QLocale.createSeparatedList') as mocked_createSeparatedList:
# GIVEN: A list of strings and the mocked Qt module.
mocked_qt.PYQT_VERSION_STR = u'4.9'
mocked_qt.qVersion.return_value = u'4.8'
mocked_createSeparatedList.return_value = u'Author 1, Author 2, and Author 3'
string_list = [u'Author 1', u'Author 2', u'Author 3']
# WHEN: We get a string build from the entries it the list and a seperator.
string_result = create_separated_list(string_list)
# THEN: We should have "Author 1, Author 2, and Author 3"
assert string_result == u'Author 1, Author 2, and Author 3', u'The string should be u\'Author 1, ' \
'Author 2, and Author 3\'.'
def create_separated_list_empty_list_test(self):
"""
Test the create_separated_list function with an empty list.
"""
with patch(u'openlp.core.lib.Qt') as mocked_qt:
# GIVEN: An empty list and the mocked Qt module.
mocked_qt.PYQT_VERSION_STR = u'4.8'
mocked_qt.qVersion.return_value = u'4.7'
string_list = []
# WHEN: We get a string build from the entries it the list and a seperator.
string_result = create_separated_list(string_list)
# THEN: We shoud have an emptry string.
assert string_result == u'', u'The string sould be empty.'
def create_separated_list_with_one_item_test(self):
"""
Test the create_separated_list function with a list consisting of only one entry.
"""
with patch(u'openlp.core.lib.Qt') as mocked_qt:
# GIVEN: A list with a string and the mocked Qt module.
mocked_qt.PYQT_VERSION_STR = u'4.8'
mocked_qt.qVersion.return_value = u'4.7'
string_list = [u'Author 1']
# WHEN: We get a string build from the entries it the list and a seperator.
string_result = create_separated_list(string_list)
# THEN: We should have "Author 1"
assert string_result == u'Author 1', u'The string should be u\'Author 1\'.'
def create_separated_list_with_two_items_test(self):
"""
Test the create_separated_list function with a list of two entries.
"""
with patch(u'openlp.core.lib.Qt') as mocked_qt, patch(u'openlp.core.lib.translate') as mocked_translate:
# GIVEN: A list of strings and the mocked Qt module.
mocked_qt.PYQT_VERSION_STR = u'4.8'
mocked_qt.qVersion.return_value = u'4.7'
mocked_translate.return_value = u'%s and %s'
string_list = [u'Author 1', u'Author 2']
# WHEN: We get a string build from the entries it the list and a seperator.
string_result = create_separated_list(string_list)
# THEN: We should have "Author 1 and Author 2"
assert string_result == u'Author 1 and Author 2', u'The string should be u\'Author 1 and Author 2\'.'
def create_separated_list_with_three_items_test(self):
"""
Test the create_separated_list function with a list of three items.
"""
with patch(u'openlp.core.lib.Qt') as mocked_qt, patch(u'openlp.core.lib.translate') as mocked_translate:
# GIVEN: A list with a string and the mocked Qt module.
mocked_qt.PYQT_VERSION_STR = u'4.8'
mocked_qt.qVersion.return_value = u'4.7'
# Always return the untranslated string.
mocked_translate.side_effect = lambda module, string_to_translate, comment: string_to_translate
string_list = [u'Author 1', u'Author 2', u'Author 3']
# WHEN: We get a string build from the entries it the list and a seperator.
string_result = create_separated_list(string_list)
# THEN: We should have "Author 1, Author 2, and Author 3"
assert string_result == u'Author 1, Author 2, and Author 3', u'The string should be u\'Author 1, ' \
'Author 2, and Author 3\'.'

View File

@ -2,13 +2,14 @@
Package to test the openlp.core.lib package.
"""
import os
from unittest import TestCase
from mock import MagicMock
from openlp.core.lib import Registry
TESTPATH = os.path.abspath(os.path.join(os.path.dirname(__file__), u'..', u'..', u'resources'))
class TestRegistry(TestCase):
def registry_service_test(self):

View File

@ -3,10 +3,9 @@
"""
import os
import cPickle
from unittest import TestCase
from mock import MagicMock
from openlp.core.lib import ServiceItem, Registry

View File

@ -0,0 +1,8 @@
import sip
sip.setapi(u'QDate', 2)
sip.setapi(u'QDateTime', 2)
sip.setapi(u'QString', 2)
sip.setapi(u'QTextStream', 2)
sip.setapi(u'QTime', 2)
sip.setapi(u'QUrl', 2)
sip.setapi(u'QVariant', 2)

View File

@ -0,0 +1,83 @@
"""
Package to test the openlp.core.ui package.
"""
from unittest import TestCase
from mock import MagicMock, patch
from openlp.core.lib import Registry
from openlp.core.ui import filerenameform
from PyQt4 import QtGui, QtTest
class TestStartFileRenameForm(TestCase):
def setUp(self):
"""
Create the UI
"""
registry = Registry.create()
self.app = QtGui.QApplication([])
self.main_window = QtGui.QMainWindow()
Registry().register(u'main_window', self.main_window)
self.form = filerenameform.FileRenameForm()
def tearDown(self):
"""
Delete all the C++ objects at the end so that we don't have a segfault
"""
del self.form
del self.main_window
del self.app
def window_title_test(self):
"""
Test the windowTitle of the FileRenameDialog
"""
# GIVEN: A mocked QDialog.exec_() method
with patch(u'PyQt4.QtGui.QDialog.exec_') as mocked_exec:
# WHEN: The form is executed with no args
self.form.exec_()
# THEN: the window title is set correctly
self.assertEqual(self.form.windowTitle(), u'File Rename', u'The window title should be "File Rename"')
# WHEN: The form is executed with False arg
self.form.exec_(False)
# THEN: the window title is set correctly
self.assertEqual(self.form.windowTitle(), u'File Rename', u'The window title should be "File Rename"')
# WHEN: The form is executed with True arg
self.form.exec_(True)
# THEN: the window title is set correctly
self.assertEqual(self.form.windowTitle(), u'File Copy', u'The window title should be "File Copy"')
def line_edit_focus_test(self):
"""
Regression test for bug1067251
Test that the fileNameEdit setFocus has called with True when executed
"""
# GIVEN: A mocked QDialog.exec_() method and mocked fileNameEdit.setFocus() method.
with patch(u'PyQt4.QtGui.QDialog.exec_') as mocked_exec:
mocked_set_focus = MagicMock()
self.form.fileNameEdit.setFocus = mocked_set_focus
# WHEN: The form is executed
self.form.exec_()
# THEN: the setFocus method of the fileNameEdit has been called with True
mocked_set_focus.assert_called_with()
def file_name_validation_test(self):
"""
Test the fileNameEdit validation
"""
# GIVEN: QLineEdit with a validator set with illegal file name characters.
# WHEN: 'Typing' a string containing invalid file characters.
QtTest.QTest.keyClicks(self.form.fileNameEdit, u'I/n\\v?a*l|i<d> \F[i\l]e" :N+a%me')
# THEN: The text in the QLineEdit should be the same as the input string with the invalid chatacters filtered
# out.
self.assertEqual(self.form.fileNameEdit.text(), u'Invalid File Name')

View File

@ -0,0 +1,43 @@
"""
Package to test the openlp.core.lib package.
"""
from unittest import TestCase
from mock import MagicMock
from PyQt4 import QtGui
from openlp.core.lib import Registry, ScreenList
from openlp.core.ui.mainwindow import MainWindow
class TestStartNoteDialog(TestCase):
def setUp(self):
"""
Create the UI
"""
Registry.create()
self.app = QtGui.QApplication([])
ScreenList.create(self.app.desktop())
Registry().register(u'application', MagicMock())
self.main_window = MainWindow()
self.service_manager = Registry().get(u'service_manager')
def tearDown(self):
"""
Delete all the C++ objects at the end so that we don't have a segfault
"""
del self.main_window
del self.app
def basic_service_manager_test(self):
"""
Test the Service Manager display functionality
"""
# GIVEN: A New Service Manager instance
# WHEN I have an empty display
# THEN the count of items should be zero
self.assertEqual(self.service_manager.service_manager_list.topLevelItemCount(), 0,
u'The service manager list should be empty ')

View File

@ -2,11 +2,13 @@
Package to test the openlp.core.ui package.
"""
from unittest import TestCase
from mock import patch
from PyQt4 import QtCore, QtGui, QtTest
from openlp.core.lib import Registry
from openlp.core.ui import servicenoteform
from PyQt4 import QtCore, QtGui, QtTest
class TestStartNoteDialog(TestCase):

View File

@ -2,11 +2,13 @@
Package to test the openlp.core.ui package.
"""
from unittest import TestCase
from mock import MagicMock, patch
from PyQt4 import QtCore, QtGui, QtTest
from openlp.core.lib import Registry
from openlp.core.ui import starttimeform
from PyQt4 import QtCore, QtGui, QtTest
class TestStartTimeDialog(TestCase):