forked from openlp/openlp
Head
This commit is contained in:
commit
8e16fc9d77
@ -30,6 +30,7 @@
|
|||||||
The :mod:`lib` module contains most of the components and libraries that make
|
The :mod:`lib` module contains most of the components and libraries that make
|
||||||
OpenLP work.
|
OpenLP work.
|
||||||
"""
|
"""
|
||||||
|
from distutils.version import LooseVersion
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
|
|
||||||
@ -366,23 +367,23 @@ def create_separated_list(stringlist):
|
|||||||
``stringlist``
|
``stringlist``
|
||||||
List of unicode strings
|
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)
|
return QtCore.QLocale().createSeparatedList(stringlist)
|
||||||
if not stringlist:
|
if not stringlist:
|
||||||
return u''
|
return u''
|
||||||
elif len(stringlist) == 1:
|
elif len(stringlist) == 1:
|
||||||
return stringlist[0]
|
return stringlist[0]
|
||||||
elif len(stringlist) == 2:
|
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])
|
'Locale list separator: 2 items') % (stringlist[0], stringlist[1])
|
||||||
else:
|
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])
|
u'Locale list separator: end') % (stringlist[-2], stringlist[-1])
|
||||||
for index in reversed(range(1, len(stringlist) - 2)):
|
for index in reversed(range(1, len(stringlist) - 2)):
|
||||||
merged = translate('OpenLP.core.lib', '%1, %2',
|
merged = translate('OpenLP.core.lib', '%s, %s',
|
||||||
u'Locale list separator: middle') % (stringlist[index], merged)
|
u'Locale list separator: middle') % (stringlist[index], merged)
|
||||||
return translate('OpenLP.core.lib', '%1, %2',
|
return translate('OpenLP.core.lib', '%s, %s', u'Locale list separator: start') % (stringlist[0], merged)
|
||||||
u'Locale list separator: start') % (stringlist[0], merged)
|
|
||||||
|
|
||||||
|
|
||||||
from registry import Registry
|
from registry import Registry
|
||||||
|
@ -34,18 +34,18 @@ from PyQt4 import QtGui
|
|||||||
|
|
||||||
from filerenamedialog import Ui_FileRenameDialog
|
from filerenamedialog import Ui_FileRenameDialog
|
||||||
|
|
||||||
from openlp.core.lib import translate
|
from openlp.core.lib import translate, Registry
|
||||||
|
|
||||||
|
|
||||||
class FileRenameForm(QtGui.QDialog, Ui_FileRenameDialog):
|
class FileRenameForm(QtGui.QDialog, Ui_FileRenameDialog):
|
||||||
"""
|
"""
|
||||||
The file rename dialog
|
The file rename dialog
|
||||||
"""
|
"""
|
||||||
def __init__(self, parent):
|
def __init__(self):
|
||||||
"""
|
"""
|
||||||
Constructor
|
Constructor
|
||||||
"""
|
"""
|
||||||
QtGui.QDialog.__init__(self, parent)
|
QtGui.QDialog.__init__(self, self.main_window)
|
||||||
self.setupUi(self)
|
self.setupUi(self)
|
||||||
|
|
||||||
def exec_(self, copy=False):
|
def exec_(self, copy=False):
|
||||||
@ -56,4 +56,15 @@ class FileRenameForm(QtGui.QDialog, Ui_FileRenameDialog):
|
|||||||
self.setWindowTitle(translate('OpenLP.FileRenameForm', 'File Copy'))
|
self.setWindowTitle(translate('OpenLP.FileRenameForm', 'File Copy'))
|
||||||
else:
|
else:
|
||||||
self.setWindowTitle(translate('OpenLP.FileRenameForm', 'File Rename'))
|
self.setWindowTitle(translate('OpenLP.FileRenameForm', 'File Rename'))
|
||||||
|
self.fileNameEdit.setFocus()
|
||||||
return QtGui.QDialog.exec_(self)
|
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)
|
||||||
|
@ -62,7 +62,7 @@ class ThemeManager(QtGui.QWidget):
|
|||||||
Registry().register(u'theme_manager', self)
|
Registry().register(u'theme_manager', self)
|
||||||
self.settingsSection = u'themes'
|
self.settingsSection = u'themes'
|
||||||
self.themeForm = ThemeForm(self)
|
self.themeForm = ThemeForm(self)
|
||||||
self.fileRenameForm = FileRenameForm(self)
|
self.fileRenameForm = FileRenameForm()
|
||||||
# start with the layout
|
# start with the layout
|
||||||
self.layout = QtGui.QVBoxLayout(self)
|
self.layout = QtGui.QVBoxLayout(self)
|
||||||
self.layout.setSpacing(0)
|
self.layout.setSpacing(0)
|
||||||
|
@ -116,6 +116,23 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
|
|||||||
self.findVerseSplit = re.compile(u'---\[\]---\n', re.UNICODE)
|
self.findVerseSplit = re.compile(u'---\[\]---\n', re.UNICODE)
|
||||||
self.whitespace = re.compile(r'\W+', 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):
|
def initialise(self):
|
||||||
"""
|
"""
|
||||||
Set up the form for when it is displayed.
|
Set up the form for when it is displayed.
|
||||||
|
@ -40,7 +40,13 @@ import os
|
|||||||
import sys
|
import sys
|
||||||
from distutils.version import LooseVersion
|
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 = {
|
VERS = {
|
||||||
'Python': '2.6',
|
'Python': '2.6',
|
||||||
@ -48,7 +54,7 @@ VERS = {
|
|||||||
'Qt4': '4.6',
|
'Qt4': '4.6',
|
||||||
'sqlalchemy': '0.5',
|
'sqlalchemy': '0.5',
|
||||||
# pyenchant 1.6 required on Windows
|
# 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
|
# pywin32
|
||||||
@ -84,7 +90,7 @@ OPTIONAL_MODULES = [
|
|||||||
('sqlite', ' (SQLite 2 support)'),
|
('sqlite', ' (SQLite 2 support)'),
|
||||||
('MySQLdb', ' (MySQL support)'),
|
('MySQLdb', ' (MySQL support)'),
|
||||||
('psycopg2', ' (PostgreSQL support)'),
|
('psycopg2', ' (PostgreSQL support)'),
|
||||||
('pytest', ' (testing framework)'),
|
('nose', ' (testing framework)'),
|
||||||
]
|
]
|
||||||
|
|
||||||
w = sys.stdout.write
|
w = sys.stdout.write
|
||||||
@ -176,7 +182,7 @@ def main():
|
|||||||
for m in OPTIONAL_MODULES:
|
for m in OPTIONAL_MODULES:
|
||||||
check_module(m[0], text=m[1])
|
check_module(m[0], text=m[1])
|
||||||
|
|
||||||
if is_win:
|
if IS_WIN:
|
||||||
print('Checking for Windows specific modules...')
|
print('Checking for Windows specific modules...')
|
||||||
for m in WIN32_MODULES:
|
for m in WIN32_MODULES:
|
||||||
check_module(m)
|
check_module(m)
|
||||||
|
@ -7,7 +7,7 @@ from datetime import datetime, timedelta
|
|||||||
from mock import MagicMock, patch
|
from mock import MagicMock, patch
|
||||||
|
|
||||||
from openlp.core.lib import str_to_bool, translate, check_directory_exists, get_text_file_string, build_icon, \
|
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):
|
class TestLib(TestCase):
|
||||||
|
|
||||||
@ -308,14 +308,14 @@ class TestLib(TestCase):
|
|||||||
file_path = u'path/to/file'
|
file_path = u'path/to/file'
|
||||||
thumb_path = u'path/to/thumb'
|
thumb_path = u'path/to/thumb'
|
||||||
mocked_os.path.exists.return_value = False
|
mocked_os.path.exists.return_value = False
|
||||||
|
|
||||||
# WHEN: we run the validate_thumb() function
|
# WHEN: we run the validate_thumb() function
|
||||||
result = validate_thumb(file_path, thumb_path)
|
result = validate_thumb(file_path, thumb_path)
|
||||||
|
|
||||||
# THEN: we should have called a few functions, and the result should be False
|
# THEN: we should have called a few functions, and the result should be False
|
||||||
mocked_os.path.exists.assert_called_with(thumb_path)
|
mocked_os.path.exists.assert_called_with(thumb_path)
|
||||||
assert result is False, u'The result should be False'
|
assert result is False, u'The result should be False'
|
||||||
|
|
||||||
def validate_thumb_file_exists_and_newer_test(self):
|
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
|
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)
|
thumb_mocked_stat.st_mtime = datetime.now() - timedelta(seconds=10)
|
||||||
mocked_os.path.exists.return_value = True
|
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
|
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
|
# WHEN: we run the validate_thumb() function
|
||||||
result = validate_thumb(file_path, thumb_path)
|
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(file_path)
|
||||||
mocked_os.stat.assert_any_call(thumb_path)
|
mocked_os.stat.assert_any_call(thumb_path)
|
||||||
assert result is False, u'The result should be False'
|
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\'.'
|
||||||
|
83
tests/interfaces/openlp_core_ui/test_filerenamedialog.py
Normal file
83
tests/interfaces/openlp_core_ui/test_filerenamedialog.py
Normal 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')
|
Loading…
Reference in New Issue
Block a user